SkinBase.cpp
上传用户:weijiexitu
上传日期:2007-01-18
资源大小:54k
文件大小:35k
源码类别:

菜单

开发平台:

WINDOWS

  1. // SkinBase.cpp: implementation of the CSkinBase class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "SkinBase.h"
  6. #include "wclassdefines.h"
  7. #include "winclasses.h"
  8. //#define ACTIVATE_VIEWER
  9. //#include "imageviewer.h"
  10. #include <afxpriv.h>
  11. #ifdef _DEBUG
  12. #undef THIS_FILE
  13. static char THIS_FILE[]=__FILE__;
  14. #define new DEBUG_NEW
  15. #endif
  16. // for transparency
  17. typedef BOOL (WINAPI *LPSetLayeredWindowAttributes)
  18. (
  19.   HWND hwnd,           // handle to the layered window
  20.   COLORREF crKey,      // specifies the color key
  21.   BYTE bAlpha,         // value for the blend function
  22.   DWORD dwFlags        // action
  23. );
  24. #ifndef SPI_SETMENUFADE
  25. #define SPI_GETMENUFADE 0x1012
  26. #define SPI_SETMENUFADE 0x1013
  27. #endif
  28. #ifndef WS_EX_LAYERED
  29. #define WS_EX_LAYERED           0x00080000
  30. // win 2000 layered windows support
  31. #define LWA_COLORKEY            0x00000001
  32. #define LWA_ALPHA               0x00000002
  33. #define ULW_COLORKEY            0x00000001
  34. #define ULW_ALPHA               0x00000002
  35. #define ULW_OPAQUE              0x00000004
  36. #endif
  37. //////////////////////////////////////////////////////////////////////
  38. // Construction/Destruction
  39. //////////////////////////////////////////////////////////////////////
  40. int CSkinBase::s_nOSVer = -1;
  41. PFNTRANSPARENTBLT CSkinBase::s_pfnFastTransparentBlt = NULL;
  42. PFNGRADIENTFILL CSkinBase::s_pfnFastGradientFill = NULL;
  43. BOOL CSkinBase::s_bThemingEnabled = (GetOS() >= SBOS_XP);
  44. // don't use fast trasparent blt on win95/98 because msimg32.dll has a resource leak
  45. BOOL CSkinBase::s_bSupportsFastTransparentBlt = (GetOS() < SBOS_ME) ? FALSE : -1;
  46. BOOL CSkinBase::s_bSupportsFastGradientFill = (GetOS() < SBOS_ME) ? FALSE : -1;
  47. CSkinBase::CSkinBase()
  48. {
  49. }
  50. CSkinBase::~CSkinBase()
  51. {
  52. }
  53. int CSkinBase::GetOS()
  54. {
  55. if (s_nOSVer == -1) // first time
  56. {
  57. OSVERSIONINFO vinfo;
  58. vinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  59. BOOL rslt = GetVersionEx(&vinfo);
  60. if (rslt)
  61. {
  62. switch (vinfo.dwPlatformId)
  63. {
  64. case VER_PLATFORM_WIN32_NT:
  65. switch (vinfo.dwMajorVersion)
  66. {
  67. case 3: // nt351
  68. ASSERT (0); // not supported
  69. break;
  70. case 4: // nt4
  71. s_nOSVer = SBOS_NT4;
  72. break;
  73. case 5: // >= w2k
  74. switch (vinfo.dwMinorVersion)
  75. {
  76. case 0: // w2k
  77. s_nOSVer = SBOS_2K;
  78. break;
  79. case 1: // xp
  80. s_nOSVer = SBOS_XP;
  81. break;
  82. default: // > xp
  83. s_nOSVer = SBOS_XPP;
  84. break;
  85. }
  86. break;
  87. default: // > xp
  88. s_nOSVer = SBOS_XPP;
  89. break;
  90. }
  91. break;
  92. case VER_PLATFORM_WIN32_WINDOWS:
  93. ASSERT (vinfo.dwMajorVersion == 4);
  94. switch (vinfo.dwMinorVersion)
  95. {
  96. case 0: // nt4
  97. s_nOSVer = SBOS_95;
  98. break;
  99. case 10: // xp
  100. s_nOSVer = SBOS_98;
  101. break;
  102. case 90: // > xp
  103. s_nOSVer = SBOS_ME;
  104. break;
  105. default:
  106. ASSERT (0);
  107. break;
  108. }
  109. break;
  110. default:
  111. ASSERT (0);
  112. break;
  113. }
  114. }
  115. }
  116. return s_nOSVer;
  117. }
  118. BOOL CSkinBase::SupportsFastTransparentBlt()
  119. {
  120. if (s_bSupportsFastTransparentBlt == -1) // first time
  121. {
  122. HINSTANCE hInst = LoadLibrary("msimg32.dll");
  123. if (hInst)
  124. {
  125. s_pfnFastTransparentBlt = (PFNTRANSPARENTBLT)GetProcAddress(hInst, "TransparentBlt");
  126. s_bSupportsFastTransparentBlt = (s_pfnFastTransparentBlt != NULL);
  127. }
  128. else
  129. s_bSupportsFastTransparentBlt = FALSE;
  130. }
  131. return s_bSupportsFastTransparentBlt;
  132. }
  133. BOOL CSkinBase::SupportsFastGradientFill()
  134. {
  135. if (s_bSupportsFastGradientFill == -1) // first time
  136. {
  137. HINSTANCE hInst = LoadLibrary("msimg32.dll");
  138. if (hInst)
  139. {
  140. s_pfnFastGradientFill = (PFNGRADIENTFILL)GetProcAddress(hInst, "GradientFill");
  141. s_bSupportsFastGradientFill = (s_pfnFastGradientFill != NULL);
  142. }
  143. else
  144. s_bSupportsFastGradientFill = FALSE;
  145. }
  146. return s_bSupportsFastGradientFill;
  147. }
  148. BOOL CSkinBase::GradientFill(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
  149. {
  150. if (!lpRect)
  151. return FALSE;
  152. if (::IsRectEmpty(lpRect))
  153. return FALSE;
  154. if (crFrom == crTo)
  155. {
  156. pDCDest->FillSolidRect(lpRect, crFrom);
  157. return TRUE;
  158. }
  159. if (GradientFillFast(pDCDest, lpRect, crFrom, crTo, bHorz))
  160. return TRUE;
  161. // else
  162. return GradientFillSlow(pDCDest, lpRect, crFrom, crTo, bHorz);
  163. }
  164. BOOL CSkinBase::TransparentBlt(CDC* pDCDest, 
  165.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  166.    CDC* pDCSrc, 
  167.    int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, 
  168.    UINT crTransparent)
  169. {
  170. if (nWidthDest < 1) 
  171. return FALSE;
  172. if (nWidthSrc < 1) 
  173. return FALSE; 
  174. if (nHeightDest < 1) 
  175. return FALSE;
  176. if (nHeightSrc < 1) 
  177. return FALSE;
  178. if (TransparentBltFast(pDCDest, 
  179. nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  180. pDCSrc, 
  181. nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,  
  182. crTransparent))
  183. return TRUE;
  184. // else 
  185. return TransparentBltSlow(pDCDest, 
  186. nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  187. pDCSrc, 
  188. nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,  
  189. crTransparent);
  190. }
  191. BOOL CSkinBase::TransparentBltFast(CDC* pDCDest, 
  192.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  193.    CDC* pDCSrc,   
  194.    int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,  
  195.    UINT crTransparent) 
  196. {
  197. if (!SupportsFastTransparentBlt() || !s_pfnFastTransparentBlt)
  198. return FALSE;
  199. return s_pfnFastTransparentBlt(*pDCDest, 
  200. nXOriginDest, 
  201. nYOriginDest, 
  202. nWidthDest, 
  203. nHeightDest,
  204. *pDCSrc, 
  205. nXOriginSrc, 
  206. nYOriginSrc, 
  207. nWidthSrc, 
  208. nHeightSrc,    
  209. crTransparent);
  210. }
  211. BOOL CSkinBase::TransparentBltSlow(CDC* pDCDest, 
  212.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  213.    CDC* pDCSrc,   
  214.    int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,  
  215.    UINT crTransparent) 
  216. {
  217. CDC dcMem, dcMask;
  218. dcMask.CreateCompatibleDC(pDCDest);
  219. dcMem.CreateCompatibleDC(pDCDest);
  220. CBitmap bmMask, bmMem;
  221. // copy src bitmap to mem dc
  222. bmMem.CreateCompatibleBitmap(pDCDest, nWidthSrc, nHeightSrc);
  223. CBitmap* pOldBMMem = dcMem.SelectObject(&bmMem);
  224. dcMem.BitBlt(0, 0, nWidthSrc, nHeightSrc, pDCSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
  225. // ShowDC(dcMem);
  226. // Create monochrome bitmap for the mask
  227. bmMask.CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL);
  228. CBitmap* pOldBMMask = dcMask.SelectObject(&bmMask);
  229. dcMem.SetBkColor(crTransparent);
  230. // Create the mask from the memory DC
  231. dcMask.BitBlt(0, 0, nWidthSrc, nHeightSrc, &dcMem, 0, 0, SRCCOPY);
  232. // ShowDC(dcMask);
  233. // Set the background in dcMem to black. Using SRCPAINT with black
  234. // and any other color results in the other color, thus making
  235. // black the transparent color
  236. dcMem.SetBkColor(RGB(0,0,0));
  237. dcMem.SetTextColor(RGB(255,255,255));
  238. dcMem.BitBlt(0, 0, nWidthSrc, nHeightSrc, &dcMask, 0, 0, SRCAND);
  239. // ShowDC(dcMem);
  240. // Set the foreground to black. See comment above.
  241. // pDCDest->SetStretchBltMode(COLORONCOLOR);
  242. pDCDest->SetStretchBltMode(HALFTONE);
  243. pDCDest->SetBkColor(RGB(255,255,255));
  244. pDCDest->SetTextColor(RGB(0,0,0));
  245. // CPoint ptOrg;
  246. // ::GetBrushOrgEx(*pDCDest, &ptOrg);
  247. // ::SetBrushOrgEx(*pDCDest, 0, 0, &ptOrg);
  248. if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
  249. {
  250. pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
  251. // ShowDC(*pDCDest);
  252. }
  253. else
  254. {
  255. pDCDest->StretchBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, 
  256. &dcMask, 0, 0, nWidthSrc, nHeightSrc, SRCAND);
  257. // ShowDC(*pDCDest);
  258. }
  259. // Combine the foreground with the background
  260. if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
  261. {
  262. pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCPAINT);
  263. // ShowDC(*pDCDest);
  264. }
  265. else
  266. {
  267. pDCDest->StretchBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, 
  268. &dcMem, 0, 0, nWidthSrc, nHeightSrc, SRCPAINT);
  269. // ShowDC(*pDCDest);
  270. }
  271. dcMask.SelectObject(pOldBMMask);
  272. dcMem.SelectObject(pOldBMMem);
  273. return TRUE;
  274. }
  275. /*
  276. BOOL CSkinBase::TransparentBltSlow(CDC* pDCDest, 
  277.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  278.    CDC* pDCSrc,   
  279.    int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,  
  280.    UINT crTransparent) 
  281. {
  282. CDC dcMem, dcMask;
  283. dcMask.CreateCompatibleDC(pDCDest);
  284. dcMem.CreateCompatibleDC(pDCDest);
  285. CBitmap bmMask, bmMem;
  286. // copy src bitmap to mem dc
  287. bmMem.CreateCompatibleBitmap(pDCDest, nWidthDest, nHeightDest);
  288. CBitmap* pOldBMMem = dcMem.SelectObject(&bmMem);
  289. dcMem.SetStretchBltMode(HALFTONE);
  290. CPoint ptOrg;
  291. ::GetBrushOrgEx(dcMem, &ptOrg);
  292. ::SetBrushOrgEx(dcMem, 0, 0, &ptOrg);
  293. dcMem.StretchBlt(0, 0, nWidthDest, nHeightDest, 
  294. pDCSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
  295. // ShowDC(dcMem);
  296. // Create monochrome bitmap for the mask
  297. bmMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);
  298. CBitmap* pOldBMMask = dcMask.SelectObject(&bmMask);
  299. dcMem.SetBkColor(crTransparent);
  300. // Create the mask from the memory DC
  301. dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCCOPY);
  302. // ShowDC(dcMask);
  303. // Set the background in dcMem to black. Using SRCPAINT with black
  304. // and any other color results in the other color, thus making
  305. // black the transparent color
  306. dcMem.SetBkColor(RGB(0,0,0));
  307. dcMem.SetTextColor(RGB(255,255,255));
  308. dcMem.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
  309. // ShowDC(dcMem);
  310. // Set the foreground to black. See comment above.
  311. pDCDest->SetBkColor(RGB(255,255,255));
  312. pDCDest->SetTextColor(RGB(0,0,0));
  313. pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMask, 0, 0, SRCAND);
  314. // ShowDC(*pDCDest);
  315. // Combine the foreground with the background
  316. pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, &dcMem, 0, 0, SRCPAINT);
  317. // ShowDC(*pDCDest);
  318. dcMask.SelectObject(pOldBMMask);
  319. dcMem.SelectObject(pOldBMMem);
  320. return TRUE;
  321. }
  322. */
  323. BOOL CSkinBase::GradientFillFast(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
  324. {
  325. if (!SupportsFastGradientFill() || !s_pfnFastGradientFill)
  326. return FALSE;
  327. TRIVERTEX vert[2];
  328. vert[0].x      = lpRect->left;
  329. vert[0].y      = lpRect->top;
  330. vert[0].Red    = GetRValue(crFrom) << 8;
  331. vert[0].Green  = GetGValue(crFrom) << 8;
  332. vert[0].Blue   = GetBValue(crFrom) << 8;
  333. vert[0].Alpha  = 0x0000;
  334. vert[1].x      = lpRect->right;
  335. vert[1].y      = lpRect->bottom; 
  336. vert[1].Red    = GetRValue(crTo) << 8;
  337. vert[1].Green  = GetGValue(crTo) << 8;
  338. vert[1].Blue   = GetBValue(crTo) << 8;
  339. vert[1].Alpha  = 0x0000;
  340. GRADIENT_RECT gRect = { 0, 1 };
  341. return s_pfnFastGradientFill(*pDCDest, 
  342. vert,
  343. 2,
  344. &gRect,
  345. 1,
  346. bHorz ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
  347. }
  348. BOOL CSkinBase::GradientFillSlow(CDC* pDCDest, LPRECT lpRect, COLORREF crFrom, COLORREF crTo, BOOL bHorz)
  349. {
  350. if (!pDCDest || !lpRect)
  351. return FALSE;
  352. int nWidth = lpRect->right - lpRect->left;
  353. int nHeight = lpRect->bottom - lpRect->top;
  354. if (bHorz)
  355. {
  356. for (int nX = lpRect->left; nX < lpRect->right; nX++)
  357. pDCDest->FillSolidRect(nX, lpRect->top, 1, nHeight, BlendColors(crFrom, crTo, (lpRect->right - nX) / (float)nWidth));
  358. }
  359. else
  360. {
  361. for (int nY = lpRect->top; nY < lpRect->bottom; nY++)
  362. pDCDest->FillSolidRect(lpRect->left, nY, nWidth, 1, BlendColors(crFrom, crTo, (lpRect->bottom - nY) / (float)nHeight));
  363. }
  364. return TRUE;
  365. }
  366. COLORREF CSkinBase::BlendColors(COLORREF crA, COLORREF crB, float fAmountA)
  367. {
  368. BYTE btRed = (BYTE)min(255, (int)(GetRValue(crA) * fAmountA + GetRValue(crB) * (1.0f - fAmountA)));
  369. BYTE btGreen = (BYTE)min(255, (int)(GetGValue(crA) * fAmountA + GetGValue(crB) * (1.0f - fAmountA)));
  370. BYTE btBlue = (BYTE)min(255, (int)(GetBValue(crA) * fAmountA + GetBValue(crB) * (1.0f - fAmountA)));
  371. return RGB(btRed, btGreen, btBlue);
  372. }
  373. COLORREF CSkinBase::VaryColor(COLORREF crColor, float fFactor)
  374. {
  375. BYTE btRed = (BYTE)min(255, (int)(GetRValue(crColor) * fFactor));
  376. BYTE btGreen = (BYTE)min(255, (int)(GetGValue(crColor) * fFactor));
  377. BYTE btBlue = (BYTE)min(255, (int)(GetBValue(crColor) * fFactor));
  378. return RGB(btRed, btGreen, btBlue);
  379. }
  380. HRGN CSkinBase::BitmapToRegion(CBitmap* pBmp, COLORREF color)
  381. {
  382. const DWORD RGNDATAHEADER_SIZE = sizeof(RGNDATAHEADER);
  383. const DWORD ADD_RECTS_COUNT  = 40; // number of rects to be appended
  384. // get image properties
  385. BITMAP BM = { 0 };
  386. pBmp->GetBitmap(&BM);
  387. // create temporary dc
  388. CBitmap bmpMem;
  389. CDC dc, dcMem1, dcMem2;
  390. CDC* pDC = CWnd::GetDesktopWindow()->GetDC();
  391. dcMem1.CreateCompatibleDC(pDC);
  392. dcMem2.CreateCompatibleDC(pDC);
  393. bmpMem.CreateCompatibleBitmap(pDC, BM.bmWidth, BM.bmHeight);
  394. CWnd::GetDesktopWindow()->ReleaseDC(pDC);
  395. CBitmap* pOldBM1 = dcMem1.SelectObject(pBmp);
  396. CBitmap* pOldBM2 = dcMem2.SelectObject(&bmpMem);
  397. // verify that the mask color is correct for the current bit depth
  398. color = dcMem2.SetPixel(0, 0, color);
  399. dcMem2.BitBlt(0, 0, BM.bmWidth, BM.bmHeight, &dcMem1, 0, 0, SRCCOPY);
  400. dcMem1.SelectObject(pOldBM1);
  401. dcMem1.DeleteDC();
  402. DWORD dwRectsCount = BM.bmHeight;  // number of rects in allocated buffer
  403. int  nY, nX;  // current position in mask image
  404. // where mask was found
  405. bool bWasMask; // set when mask has been found in current scan line
  406. bool bIsMask; // set when current color is mask color
  407. CRect rLine;
  408. // allocate memory for region data
  409. // region data here is set of regions that are rectangles with height 1 pixel (scan line)
  410. // that's why nRgnStart allocation is <bm.biHeight> RECTs - number of scan lines in image
  411. RGNDATAHEADER* pRgnData = (RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
  412. // get pointer to RECT table
  413. LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
  414. // zero region data header memory (header  part only)
  415. memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );
  416. // fill it by default
  417. pRgnData->dwSize = RGNDATAHEADER_SIZE;
  418. pRgnData->iType  = RDH_RECTANGLES;
  419. for ( nY = 0; nY < BM.bmHeight; nY++ )
  420. {
  421. bWasMask = true;
  422. rLine.SetRect(0, nY, 0, nY + 1);
  423. for ( nX = 0; nX < BM.bmWidth; nX++ )
  424. {
  425. // get color
  426. COLORREF crPixel = dcMem2.GetPixel(nX, nY);
  427. bIsMask = (crPixel == color);
  428. if (!bIsMask && bWasMask) // start of the rgn
  429. {
  430. rLine.left = nX;
  431. bWasMask = FALSE;
  432. }
  433. if (!bWasMask && (bIsMask || nX == BM.bmWidth - 1)) // end of rgn
  434. {
  435. bWasMask = true;
  436. rLine.right = bIsMask ? nX : nX + 1;
  437. // save current RECT
  438. // if this was a full line append to the last if it was full too
  439. BOOL bAdded = FALSE;
  440. if (pRgnData->nCount)
  441. {
  442. LPRECT pLastRect = &pRects[ pRgnData->nCount - 1];
  443. if (!pLastRect->left && !rLine.left && 
  444. pLastRect->right == BM.bmWidth - 1 && rLine.right == BM.bmWidth - 1)
  445. {
  446. pLastRect->bottom = rLine.bottom;
  447. bAdded = TRUE;
  448. }
  449. }
  450. // else add as a new line
  451. if (!bAdded)
  452. {
  453. pRects[ pRgnData->nCount++ ] = rLine;
  454. // if buffer full reallocate it with more room
  455. if ( pRgnData->nCount >= dwRectsCount )
  456. {
  457. dwRectsCount += ADD_RECTS_COUNT;
  458. // allocate new buffer
  459. LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
  460. // copy current region data to it
  461. memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
  462. // delte old region data buffer
  463. delete pRgnData;
  464. // set pointer to new regiondata buffer to current
  465. pRgnData = (RGNDATAHEADER*)pRgnDataNew;
  466. // correct pointer to RECT table
  467. pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
  468. }
  469. }
  470. }
  471. }
  472. }
  473. // create region
  474. HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
  475. CRect rBox;
  476. ::GetRgnBox(hRgn, rBox);
  477. // release region data
  478. delete pRgnData;
  479. dcMem2.SelectObject(pOldBM2);
  480. dcMem2.DeleteDC();
  481. bmpMem.DeleteObject();
  482. return hRgn;
  483. }
  484. HMENU CSkinBase::MakeMenuCopy(const CMenu* pSrc)
  485. {
  486. if (!pSrc)
  487. return NULL;
  488. CMenu menu;
  489. VERIFY (menu.CreatePopupMenu());
  490. ASSERT (::IsMenu(menu.m_hMenu));
  491. int nNumItems = pSrc->GetMenuItemCount();
  492. CString sLabel;
  493. MENUITEMINFO mii;
  494. ZeroMemory(&mii, sizeof(mii));
  495. mii.cbSize = sizeof(mii); // must fill up this field
  496. mii.fMask = MIIM_STATE | MIIM_DATA;  // get the state of the menu item
  497. for (int nItem = 0; nItem < nNumItems; nItem++)
  498. {
  499. UINT uIDItem = pSrc->GetMenuItemID(nItem);
  500. pSrc->GetMenuString(nItem, sLabel, MF_BYPOSITION);
  501. UINT uFlags = (uIDItem == 0) ? MF_SEPARATOR : (uIDItem == (UINT)-1) ? MF_POPUP : MF_STRING;
  502. // special case: if a popup menu we must copy it too
  503. if (uFlags == MF_POPUP)
  504. {
  505. HMENU hPopup = MakeMenuCopy(pSrc->GetSubMenu(nItem));
  506. ASSERT (hPopup);
  507. uIDItem = (UINT)hPopup;
  508. }
  509. menu.AppendMenu(uFlags, uIDItem, sLabel);
  510. // make sure we copy the state too
  511. ::GetMenuItemInfo(*pSrc, nItem, TRUE, &mii);
  512. ::SetMenuItemInfo(menu, nItem, TRUE, &mii);
  513. }
  514. return menu.Detach();
  515. }
  516. // this one copies the menu without deleting the root
  517. BOOL CSkinBase::CopyMenu(const CMenu* pSrc, CMenu* pDest)
  518. {
  519. ASSERT (::IsMenu(pDest->m_hMenu));
  520. if (!::IsMenu(pDest->m_hMenu))
  521. return FALSE;
  522. ASSERT (::IsMenu(pSrc->m_hMenu));
  523. if (!::IsMenu(pSrc->m_hMenu))
  524. return FALSE;
  525. // delete all the existing items
  526. while (pDest->GetMenuItemCount())
  527. pDest->DeleteMenu(0, MF_BYPOSITION);
  528. // copy across
  529. int nNumItems = pSrc->GetMenuItemCount();
  530. CString sLabel;
  531. MENUITEMINFO mii;
  532. ZeroMemory(&mii, sizeof(mii));
  533. mii.cbSize = sizeof(mii); // must fill up this field
  534. mii.fMask = MIIM_STATE | MIIM_DATA;  // get the state of the menu item
  535. for (int nItem = 0; nItem < nNumItems; nItem++)
  536. {
  537. UINT uIDItem = pSrc->GetMenuItemID(nItem);
  538. pSrc->GetMenuString(nItem, sLabel, MF_BYPOSITION);
  539. UINT uFlags = (uIDItem == 0) ? MF_SEPARATOR : (uIDItem == (UINT)-1) ? MF_POPUP : MF_STRING;
  540. // special case: if a popup menu we must copy it too
  541. if (uFlags == MF_POPUP)
  542. {
  543. HMENU hPopup = MakeMenuCopy(pSrc->GetSubMenu(nItem));
  544. ASSERT (hPopup);
  545. uIDItem = (UINT)hPopup;
  546. }
  547. pDest->AppendMenu(uFlags, uIDItem, sLabel);
  548. // make sure we copy the state too
  549. ::GetMenuItemInfo(*pSrc, nItem, TRUE, &mii);
  550. ::SetMenuItemInfo(*pDest, nItem, TRUE, &mii);
  551. }
  552. return TRUE;
  553. }
  554. BOOL CSkinBase::CopyBitmap(const CBitmap* pSrc, CBitmap* pDest)
  555. {
  556. ASSERT (pDest);
  557. if (!pDest)
  558. return FALSE;
  559. pDest->DeleteObject();
  560. if (!pSrc || !pSrc->GetSafeHandle())
  561. return FALSE;
  562. CDC* pDC = CWnd::GetDesktopWindow()->GetDC();
  563. CDC dcMem1, dcMem2;
  564. BOOL bRes = FALSE;
  565. if (dcMem1.CreateCompatibleDC(pDC) && dcMem2.CreateCompatibleDC(pDC))
  566. {
  567. BITMAP bm;
  568. ((CBitmap*)pSrc)->GetBitmap(&bm);
  569. if (pDest->CreateCompatibleBitmap(pDC, bm.bmWidth, bm.bmHeight))
  570. {
  571. ASSERT (CBitmap::FromHandle((HBITMAP)pDest->GetSafeHandle()) == pDest);
  572. CBitmap* pOldBM1 = dcMem1.SelectObject((CBitmap*)pSrc);
  573. CBitmap* pOldBM2 = dcMem2.SelectObject(pDest);
  574. dcMem2.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMem1, 0, 0, SRCCOPY);
  575. bRes = TRUE;
  576. dcMem1.SelectObject(pOldBM1);
  577. dcMem2.SelectObject(pOldBM2);
  578. }
  579. }
  580. dcMem1.DeleteDC();
  581. dcMem2.DeleteDC();
  582. CWnd::GetDesktopWindow()->ReleaseDC(pDC);
  583. ASSERT (CBitmap::FromHandle((HBITMAP)pDest->GetSafeHandle()) == pDest);
  584. HANDLE* ph = (HANDLE*)((BYTE*)pDest + 4);  // after CObject
  585. ASSERT (ph[0] == pDest->GetSafeHandle());
  586. return bRes;
  587. }
  588. BOOL CSkinBase::ExtractResource(UINT nID, LPCTSTR szType, CString& sTempFilePath, HINSTANCE hInst)
  589. {
  590. if (!hInst)
  591. hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nID), szType);
  592. if (!hInst)
  593. return FALSE;
  594. // compare time with that of module from which it was loaded
  595. CString sTempPath;
  596. CFileStatus fsRes, fsModule;
  597. CString sModulePath;
  598. ::GetModuleFileName(hInst, sModulePath.GetBuffer(MAX_PATH + 1), MAX_PATH);
  599. sModulePath.ReleaseBuffer();
  600. if (!CFile::GetStatus(sModulePath, fsModule))
  601. return FALSE;
  602. // create temp filename
  603. ::GetTempPath(MAX_PATH, sTempPath.GetBuffer(MAX_PATH));
  604. sTempPath.ReleaseBuffer();
  605. sTempFilePath.Format("%s%s_skin_%d.tmp", sTempPath, szType, nID);
  606. // see if the file has been created before
  607. if (!CFile::GetStatus(sTempFilePath, fsRes) || fsRes.m_mtime < fsModule.m_mtime)
  608. {
  609. // Load the resource into memory
  610. HRSRC hRes = FindResource(hInst, (LPCSTR)nID, szType);
  611. if (!hRes) 
  612. {
  613. TRACE("Couldn't find %s resource %d!n", szType, nID);
  614. return FALSE;
  615. }
  616. DWORD len = SizeofResource(hInst, hRes);
  617. BYTE* lpRes = (BYTE*)LoadResource(hInst, hRes);
  618. ASSERT(lpRes);
  619. CFile file;
  620. if (file.Open(sTempFilePath, CFile::modeCreate | CFile::modeWrite))
  621. {
  622. file.Write(lpRes, len);
  623. file.Close();
  624. FreeResource((HANDLE)lpRes);
  625. }
  626. else
  627. {
  628. FreeResource((HANDLE)lpRes);
  629. return FALSE;
  630. }
  631. }
  632. return TRUE;
  633. }
  634. CWnd* CSkinBase::GetChildWnd(CWnd* pParent, LPCTSTR szClass, int nID)
  635. {
  636. CWnd* pChild = pParent->GetWindow(GW_CHILD); 
  637. while (pChild)   
  638. {
  639. if (CWinClasses::IsClass(*pChild, szClass))
  640. {
  641. if (nID == -1 || pChild->GetDlgCtrlID() == nID)
  642. return pChild;
  643. }
  644. pChild = pChild->GetNextWindow();
  645. }
  646. return NULL;
  647. }
  648. BOOL CSkinBase::BitBlt(CDC* pDCDest, 
  649.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  650.    CDC* pDCSrc, int nXOriginSrc, int nYOriginSrc, 
  651.    UINT uROP,    
  652.    COLORREF crTransparent)
  653. {
  654. if (crTransparent != (COLORREF)-1)
  655. {
  656. return TransparentBlt(pDCDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  657. pDCSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest, crTransparent);
  658. }
  659. else
  660. {
  661. return pDCDest->BitBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  662. pDCSrc, nXOriginSrc, nYOriginSrc, uROP);
  663. }
  664. return TRUE;
  665. }
  666. BOOL CSkinBase::StretchBlt(CDC* pDCDest, 
  667.    int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
  668.    CDC* pDCSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,   
  669.    UINT uROP,    
  670.    COLORREF crTransparent)
  671. {
  672. // check to see if this is really just a BitBlt
  673. if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
  674. {
  675. return BitBlt(pDCDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  676.    pDCSrc, nXOriginSrc, nYOriginSrc, uROP, crTransparent);
  677. }
  678. // else pick whether its transparent or not
  679. if (crTransparent != (COLORREF)-1)
  680. {
  681. return TransparentBlt(pDCDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  682. pDCSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, crTransparent);
  683. }
  684. else
  685. {
  686. return pDCDest->StretchBlt(nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
  687. pDCSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, uROP);
  688. }
  689. return TRUE;
  690. }
  691. CString CSkinBase::GetTipText(LPCTSTR szText, BOOL bToolbar)
  692. {
  693. CString sText(szText), sTip;
  694. if (sText.IsEmpty())
  695. return "";
  696. // tip text starts at 'n' 
  697. int nStartTip = bToolbar ? sText.Find('n') : -1;
  698. if (bToolbar && nStartTip == -1) // no tip
  699. return "";
  700. sText = sText.Right(sText.GetLength() - nStartTip - 1);
  701. // strip '&' and '...' if present
  702. int nLen = sText.GetLength();
  703. sTip.Empty();
  704. for (int nPos = 0; nPos < nLen; nPos++)
  705. {
  706. if (sText[nPos] != '&' && sText[nPos] != '.')
  707. sTip += sText[nPos];
  708. }
  709. return sTip;
  710. }
  711. BOOL CSkinBase::ConvertToGrayScale(CBitmap* pBitmap, COLORREF crMask)
  712. {
  713. CDC dcTemp;
  714. dcTemp.CreateCompatibleDC(NULL);
  715. BITMAP BM;
  716. pBitmap->GetBitmap(&BM);
  717. CBitmap* pBMOld = dcTemp.SelectObject(pBitmap);
  718. // now iterate all the pixels, converting each to grayscale
  719. // a bit daggy, but....
  720. int nXPixel = BM.bmWidth;
  721. COLORREF crPixel;
  722. while (nXPixel--)
  723. {
  724. int nYPixel = BM.bmHeight;
  725. while (nYPixel--)
  726. {
  727. crPixel = dcTemp.GetPixel(nXPixel, nYPixel);
  728. // leave the mask color as-is
  729. if (crPixel == crMask)
  730. continue;
  731. const BYTE btRed = GetRValue(crPixel);
  732. const BYTE btGreen = GetGValue(crPixel);
  733. const BYTE btBlue = GetBValue(crPixel);
  734. // if gray already goto next
  735. if (btRed == btGreen && btGreen == btBlue)
  736. continue;
  737. const BYTE btGray = (BYTE)((btRed / 3) + (btGreen / 2) + (btBlue / 4));
  738. // note: SetPixelV() quicker than SetPixel()
  739. dcTemp.SetPixelV(nXPixel, nYPixel, RGB(btGray, btGray, btGray));
  740. }
  741. }
  742. dcTemp.SelectObject(pBMOld);
  743. dcTemp.DeleteDC();
  744. return TRUE;
  745. }
  746. BOOL CSkinBase::DoSysMenu(CWnd* pWnd, CPoint ptCursor, LPRECT prExclude, BOOL bCopy)
  747. {
  748. CMenu* pMenu = pWnd->GetSystemMenu(FALSE);
  749. ASSERT (pMenu);
  750. if (pMenu)
  751. {
  752. TPMPARAMS tpmp;
  753. tpmp.cbSize = sizeof(tpmp);
  754. if (prExclude)
  755. tpmp.rcExclude = *prExclude;
  756. else
  757. SetRectEmpty(&tpmp.rcExclude);
  758. UINT uAlignFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERTICAL | TPM_RIGHTBUTTON | TPM_RETURNCMD;
  759. UINT uID = 0;
  760. if (bCopy) // skinning
  761. {
  762. HMENU hSysMenu = CSkinBase::MakeMenuCopy(pMenu);
  763. ASSERT (hSysMenu);
  764. if (hSysMenu)
  765. {
  766. InitSysMenu(CMenu::FromHandle(hSysMenu), pWnd);
  767. uID = ::TrackPopupMenuEx(hSysMenu, uAlignFlags, 
  768. ptCursor.x, ptCursor.y, *pWnd, &tpmp);
  769. ::DestroyMenu(hSysMenu); // cleanup
  770. }
  771. }
  772. else
  773. {
  774. InitSysMenu(pMenu, pWnd);
  775. uID = ::TrackPopupMenuEx(pMenu->GetSafeHmenu(), uAlignFlags, 
  776. ptCursor.x, ptCursor.y, *pWnd, &tpmp);
  777. }
  778. if (uID & 0xf000) // syscommand
  779. {
  780. MSG& curMsg = AfxGetThreadState()->m_lastSentMsg;
  781. // always post this command to allow this function to unwind
  782. // correctly before the command is handled
  783. pWnd->PostMessage(WM_SYSCOMMAND, (uID & 0xfff0), MAKELPARAM(curMsg.pt.x, curMsg.pt.y));
  784. }
  785. }
  786. return TRUE;
  787. }
  788. void CSkinBase::InitSysMenu(CMenu* pMenu, CWnd* pWnd)
  789. {
  790. // iterate all the menu items looking for something resembling a sys menu item
  791. int nItem = pMenu->GetMenuItemCount();
  792. while (nItem--)
  793. {
  794. UINT uID = pMenu->GetMenuItemID(nItem);
  795. if (uID >= 0xF000)
  796. {
  797. BOOL bEnable = TRUE;
  798. switch (uID & 0xFFF0)
  799. {
  800. case SC_MINIMIZE:
  801. bEnable = (pWnd->GetStyle() & WS_MINIMIZEBOX) && !pWnd->IsIconic();
  802. break;
  803. case SC_MAXIMIZE:
  804. bEnable = (pWnd->GetStyle() & WS_MAXIMIZEBOX) && !pWnd->IsZoomed();
  805. break;
  806. case SC_RESTORE:
  807. bEnable = pWnd->IsIconic() || pWnd->IsZoomed();
  808. break;
  809. case SC_MOVE:
  810. case SC_SIZE:
  811. bEnable = !pWnd->IsIconic() && !pWnd->IsZoomed();
  812. break;
  813. }
  814. pMenu->EnableMenuItem(uID, bEnable ? MF_ENABLED : MF_GRAYED);
  815. }
  816. }
  817. // set close as default item
  818. pMenu->SetDefaultItem(SC_CLOSE);
  819. }
  820. CSize CSkinBase::GetTextExtent(CDC* pDC, LPCTSTR szText)
  821. {
  822. ASSERT (pDC && szText);
  823. if (pDC && szText)
  824. {
  825. CRect rText(0, 0, 0, SHRT_MAX);
  826. pDC->DrawText(szText, rText, DT_SINGLELINE | DT_CALCRECT);
  827. return rText.Size();
  828. }
  829. // else
  830. return 0;
  831. }
  832. const LPCTSTR WORDBREAK = "_-+=,.:;n";
  833. const int CHUNK = 32;
  834. int CSkinBase::FormatText(CDC* pDC, CString& sText, CRect& rect, UINT uDTFlags)
  835. {
  836. CString sOrgText(sText);
  837. sText.Empty();
  838. int nPos = 0, nLinePos = 0, nLen = sOrgText.GetLength();
  839. int nLastWhiteSpace = -1;
  840. int nHeight = 0;
  841. const int LINEHEIGHT = pDC->GetTextExtent("W").cy;
  842. int nLongestLine = 0;
  843. // we always allow at least one line of text
  844. BOOL bSingleLine = (uDTFlags & DT_SINGLELINE);
  845. BOOL bCalcRect = (uDTFlags & DT_CALCRECT);
  846. BOOL bEllipsis = (uDTFlags & DT_END_ELLIPSIS);
  847. BOOL bModString = (uDTFlags & DT_MODIFYSTRING);
  848. BOOL bFinished = FALSE;
  849. const int CHUNK = 32;
  850. char* pBuffer = sOrgText.GetBuffer(sOrgText.GetLength() + 1);
  851. while (!bFinished)
  852. {
  853. int nChunk = CHUNK;
  854. BOOL bLonger = TRUE;
  855. int nLinePos = 0;
  856. int nPrevPos = 0;
  857. char* pLine = pBuffer + nPos;
  858. // add chunks till we go over 
  859. BOOL bContinue = TRUE;
  860. int nWidth = 0;
  861. while (bContinue)
  862. {
  863. nChunk = min(nChunk, nLen - (nPos + nLinePos));
  864. nLinePos += nChunk;
  865. nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
  866. bContinue = (nChunk == CHUNK && nWidth < rect.Width());
  867. }
  868. // then iterate back and forth with sub chunks till we are just under
  869. for (int i = 0; i < 5; i++)
  870. {
  871. nChunk /= 2;
  872. if (nWidth == rect.Width())
  873. break;
  874. else if (nWidth > rect.Width())
  875. nLinePos -= nChunk;
  876. else
  877. nLinePos += nChunk;
  878. nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
  879. }
  880. // one final check to see we haven't ended up over 
  881. if (nWidth > rect.Width())
  882. nLinePos--;
  883. // then work back to the previous word break
  884. int nSavePos = nLinePos;
  885. while (nLinePos)
  886. {
  887. // we word break either if the current character is whitespace or
  888. // if the preceding character is a wordbreak character
  889. // or we've reached the end of the string
  890. BOOL bWordBreak = (nLinePos == nLen) || _istspace(pLine[nLinePos]) ||
  891. (strchr(WORDBREAK, pLine[nLinePos - 1]) != NULL);
  892. if (bWordBreak)
  893. break;
  894. nLinePos--;
  895. }
  896. if (!nLinePos)
  897. nLinePos = nSavePos; // single word spans entire line
  898. nWidth = pDC->GetTextExtent(pLine, nLinePos).cx;
  899. // check for last line and add ellipsis if required
  900. nHeight += LINEHEIGHT;
  901. BOOL bAddEllipsis = FALSE;
  902. if (nHeight + LINEHEIGHT > rect.Height() || bSingleLine)
  903. {
  904. if (bEllipsis && nPos + nLinePos < nLen - 1)
  905. {
  906. const int LEN_ELLIPSIS = pDC->GetTextExtent("...", 3).cx;
  907. // modify the last line to add ellipsis
  908. while (nLinePos)
  909. {
  910. nWidth = pDC->GetTextExtent(pLine, nLinePos).cx + LEN_ELLIPSIS;
  911. if (nWidth > rect.Width())
  912. nLinePos--;
  913. else
  914. break;
  915. }
  916. bAddEllipsis = TRUE;
  917. }
  918. sText += sOrgText.Mid(nPos, nLinePos);
  919. if (bAddEllipsis)
  920. sText += "...";
  921. nLongestLine = max(nLongestLine, nWidth);
  922. break;
  923. }
  924. sText += sOrgText.Mid(nPos, nLinePos);
  925. sText += 'n';
  926. nPos += nLinePos;
  927. bFinished = (nPos >= nLen - 1 || nHeight + LINEHEIGHT > rect.Height());
  928. nLongestLine = max(nLongestLine, nWidth);
  929. // jump white space at the start of the next line
  930. if (!bFinished)
  931. {
  932. while (nPos < nLen - 1)
  933. {
  934. if (!_istspace(pBuffer[nPos]))
  935. break;
  936. // else
  937. nPos++;
  938. }
  939. }
  940. }
  941. sOrgText.ReleaseBuffer();
  942. if (!bModString)
  943. sText = sOrgText;
  944. if (bCalcRect)
  945. {
  946. rect.right = rect.left + nLongestLine;
  947. rect.bottom = rect.top + nHeight;
  948. }
  949. return nHeight;
  950. }
  951. //////////////////////////////
  952. //////////////////////////////
  953. int CALLBACK CheckFontProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam)
  954. {
  955. BOOL* pPresent = (BOOL*)lParam;
  956. ASSERT (pPresent);
  957. if (pPresent && FontType == TRUETYPE_FONTTYPE) // only TT accepted for now
  958. *pPresent = TRUE; // at least one font found to match facename
  959. return 0;
  960. }
  961. BOOL CSkinBase::FontIsPresent(LPCTSTR szFaceName)
  962. {
  963. LOGFONT lf;
  964. HDC hdc = ::GetDC(NULL);
  965. lf.lfCharSet = DEFAULT_CHARSET;
  966. lf.lfPitchAndFamily = 0;
  967. lstrcpy(lf.lfFaceName, szFaceName);
  968. BOOL bPresent = FALSE;
  969. EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC)CheckFontProc, (LPARAM)&bPresent, 0);
  970. ::ReleaseDC(NULL, hdc);
  971. return bPresent;
  972. }
  973. //////////////////////////////////
  974. // theming
  975. #ifndef STAP_ALLOW_NONCLIENT
  976. #define STAP_ALLOW_NONCLIENT    (1 << 0)
  977. #define STAP_ALLOW_CONTROLS     (1 << 1)
  978. #define STAP_ALLOW_WEBCONTENT   (1 << 2)
  979. #endif
  980. typedef void (STDAPICALLTYPE* SETTHEMEAPPPROPERTIES)(DWORD);
  981. void CSkinBase::EnableTheming(BOOL bEnable)
  982. {
  983. if (GetOS() < SBOS_XP || bEnable == s_bThemingEnabled)
  984. return;
  985. static HMODULE hUXTheme = ::LoadLibrary("UXTheme.dll");
  986. if (hUXTheme)
  987. {
  988. SETTHEMEAPPPROPERTIES SetThemeAppProperties = 
  989. (SETTHEMEAPPPROPERTIES)GetProcAddress(hUXTheme, "SetThemeAppProperties");
  990. if (SetThemeAppProperties)
  991. {
  992. SetThemeAppProperties(bEnable ? 
  993. STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS | STAP_ALLOW_WEBCONTENT :
  994. 0);
  995. s_bThemingEnabled = bEnable;
  996. }
  997. }
  998. }
  999. BOOL CSkinBase::CreateThemeManifest(LPCTSTR szName, LPCTSTR szDescription)
  1000. {
  1001. // if (GetOS() < SBOS_XP)
  1002. // return FALSE;
  1003. // create the manifest only if one does not exist
  1004. CString sFilePath;
  1005. ::GetModuleFileName(NULL, sFilePath.GetBuffer(MAX_PATH + 1), MAX_PATH);
  1006. sFilePath.ReleaseBuffer();
  1007. sFilePath += ".Manifest";
  1008. CFileStatus fs;
  1009. if (CFile::GetStatus(sFilePath, fs))
  1010. return TRUE; // already exists
  1011. ASSERT (szName && strlen(szName) && szDescription && strlen(szDescription));
  1012. if (!(szName && strlen(szName) && szDescription && strlen(szDescription)))
  1013. return FALSE;
  1014. LPCTSTR szManifestFmt = " 
  1015. <?xml version='1.0' encoding='UTF-8' standalone='yes'?> 
  1016. <assembly 
  1017.     xmlns='urn:schemas-microsoft-com:asm.v1' 
  1018.     manifestVersion='1.0'> 
  1019.     <assemblyIdentity 
  1020.         version='1.0.0.0' 
  1021.         processorArchitecture='X86' 
  1022.         name='%s' 
  1023.         type='win32' 
  1024.     /> 
  1025.     <description>%s</description> 
  1026.     <dependency> 
  1027.         <dependentAssembly> 
  1028.             <assemblyIdentity 
  1029.                 type='win32' 
  1030.                 name='Microsoft.Windows.Common-Controls' 
  1031.                 version='6.0.0.0' 
  1032.                 processorArchitecture='X86' 
  1033.                 publicKeyToken='6595b64144ccf1df' 
  1034.                 language='*' 
  1035.             /> 
  1036.         </dependentAssembly> 
  1037.     </dependency> 
  1038. </assembly> ";
  1039. CString sManifest;
  1040. sManifest.Format(szManifestFmt, szName, szDescription);
  1041. CStdioFile file;
  1042. if (!file.Open(sFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeText))
  1043. return FALSE;
  1044. file.WriteString(sManifest);
  1045. file.Close();
  1046. return TRUE;
  1047. }
  1048. //////////////////////////////////////////////////////////////////////////////////////////
  1049. HICON CSkinBase::GetWindowIcon(CWnd* pWnd)
  1050. {
  1051. ASSERT (pWnd);
  1052. if (!pWnd)
  1053. return NULL;
  1054. HICON hIcon = pWnd->GetIcon(FALSE); // small icon
  1055. if (!hIcon)
  1056. hIcon = pWnd->GetIcon(TRUE); // large icon
  1057. if (!hIcon)
  1058. {
  1059. WNDCLASS wndcls;
  1060. CString sClass(CWinClasses::GetClass(*pWnd));
  1061. if (GetClassInfo(AfxGetInstanceHandle(), sClass, &wndcls))
  1062. hIcon = wndcls.hIcon;
  1063. }
  1064. return hIcon;
  1065. }