Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1222 lines
34 KiB

  1. /*****************************************************************************\
  2. FILE: PreviewTh.cpp
  3. DESCRIPTION:
  4. This code will display a preview of the currently selected
  5. visual styles.
  6. BryanSt 5/5/2000
  7. Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
  8. \*****************************************************************************/
  9. #include "priv.h"
  10. #include "PreviewTh.h"
  11. #include "PreviewSM.h"
  12. #include "classfactory.h"
  13. // Old predef for Patterns
  14. #define CXYDESKPATTERN 8
  15. // Async Bitmap loading
  16. #define PREVIEW_PICTURE_FILENAME TEXT("PrePict.htm")
  17. #define WM_HTML_BITMAP (WM_USER + 100)
  18. #define WM_ASYNC_BITMAP (WM_HTML_BITMAP + 1)
  19. typedef struct{
  20. HWND hwnd;
  21. HBITMAP hbmp;
  22. DWORD id;
  23. WCHAR szFile[MAX_PATH];
  24. } ASYNCWALLPARAM, * PASYNCWALLPARAM;
  25. // Window Class Name
  26. #define THEMEPREV_CLASS TEXT("ThemePreview")
  27. //============================================================================================================
  28. // *** Globals ***
  29. //============================================================================================================
  30. //===========================
  31. // *** Class Internals & Helpers ***
  32. //===========================
  33. //===========================
  34. // *** IThemePreview Interface ***
  35. //===========================
  36. extern LPCWSTR s_Icons[];
  37. HRESULT CPreviewTheme::UpdatePreview(IN IPropertyBag * pPropertyBag)
  38. {
  39. HRESULT hr = E_INVALIDARG;
  40. DEBUG_CODE(DebugStartWatch());
  41. if (pPropertyBag && _hwndPrev)
  42. {
  43. SYSTEMMETRICSALL systemMetricsAll = {0};
  44. hr = SHPropertyBag_ReadByRef(pPropertyBag, SZ_PBPROP_SYSTEM_METRICS, &systemMetricsAll, sizeof(systemMetricsAll));
  45. BOOL fSysMetDirty = (memcmp(&systemMetricsAll, &_systemMetricsAll, sizeof(SYSTEMMETRICSALL)) != 0);
  46. if (fSysMetDirty)
  47. memcpy(&_systemMetricsAll, &systemMetricsAll, sizeof(SYSTEMMETRICSALL));
  48. _putBackground(NULL, TRUE, 0);
  49. if (_fShowBack)
  50. {
  51. WCHAR szBackgroundPath[MAX_PATH];
  52. DWORD dwBackgroundTile;
  53. // See the list of Property Bag names for Themes in shpriv.idl
  54. hr = SHPropertyBag_ReadStr(pPropertyBag, SZ_PBPROP_BACKGROUND_PATH, szBackgroundPath, ARRAYSIZE(szBackgroundPath));
  55. hr = SHPropertyBag_ReadDWORD(pPropertyBag, SZ_PBPROP_BACKGROUND_TILE, &dwBackgroundTile);
  56. if ((lstrcmp(szBackgroundPath, _szBackgroundPath) != 0) || (_iTileMode != (int)dwBackgroundTile))
  57. {
  58. lstrcpy(_szBackgroundPath, szBackgroundPath);
  59. _putBackground(_szBackgroundPath, FALSE, dwBackgroundTile);
  60. }
  61. }
  62. if (_fShowVS)
  63. {
  64. WCHAR szVSPath[MAX_PATH];
  65. WCHAR szVSColor[MAX_PATH];
  66. WCHAR szVSSize[MAX_PATH];
  67. hr = SHPropertyBag_ReadStr(pPropertyBag, SZ_PBPROP_VISUALSTYLE_PATH, szVSPath, ARRAYSIZE(szVSPath));
  68. hr = SHPropertyBag_ReadStr(pPropertyBag, SZ_PBPROP_VISUALSTYLE_COLOR, szVSColor, ARRAYSIZE(szVSColor));
  69. hr = SHPropertyBag_ReadStr(pPropertyBag, SZ_PBPROP_VISUALSTYLE_SIZE, szVSSize, ARRAYSIZE(szVSSize));
  70. if ((lstrcmp(szVSPath, _szVSPath) != 0) ||
  71. (lstrcmp(szVSColor, _szVSColor) != 0) ||
  72. (lstrcmp(szVSSize, _szVSSize) != 0) ||
  73. fSysMetDirty)
  74. {
  75. lstrcpy(_szVSPath, szVSPath);
  76. lstrcpy(_szVSColor, szVSColor);
  77. lstrcpy(_szVSSize, szVSSize);
  78. _putVisualStyle(_szVSPath, _szVSColor, _szVSSize, &_systemMetricsAll);
  79. }
  80. }
  81. if (_fShowIcons)
  82. {
  83. _putIcons(pPropertyBag);
  84. }
  85. }
  86. DEBUG_CODE(TraceMsg(TF_THEMEUI_PERF, "CPreviewTheme::UpdatePreview() returned %#08lx. Time=%lums", hr, DebugStopWatch()));
  87. return hr;
  88. }
  89. HRESULT CPreviewTheme::CreatePreview(IN HWND hwndParent, IN DWORD dwFlags, IN DWORD dwStyle, IN DWORD dwExStyle, IN int x, IN int y, IN int nWidth, IN int nHeight, IN IPropertyBag * pPropertyBag, IN DWORD dwCtrlID)
  90. {
  91. HRESULT hr = S_OK;
  92. DEBUG_CODE(DebugStartWatch());
  93. g_bMirroredOS = IS_MIRRORING_ENABLED();
  94. _fRTL = IS_WINDOW_RTL_MIRRORED(hwndParent);
  95. _hwndPrev = CreateWindowEx(dwExStyle, THEMEPREV_CLASS, L"Preview", dwStyle, x, y, nWidth, nHeight, hwndParent, (HMENU)IntToPtr(dwCtrlID), HINST_THISDLL, NULL);
  96. if (_hwndPrev)
  97. {
  98. SetWindowLongPtr(_hwndPrev, GWLP_USERDATA, (LONG_PTR)this);
  99. if (_pThumb)
  100. _pThumb->Init(_hwndPrev, WM_HTML_BITMAP);
  101. GetClientRect(_hwndPrev, &_rcOuter);
  102. if (dwFlags & TMPREV_SHOWMONITOR)
  103. {
  104. _fShowMon = TRUE;
  105. BITMAP bmMon;
  106. GetObject(_hbmMon, sizeof(bmMon), &bmMon);
  107. int ox = (RECTWIDTH(_rcOuter) - bmMon.bmWidth) / 2;
  108. int oy = (RECTHEIGHT(_rcOuter) - bmMon.bmHeight) / 2;
  109. RECT rc = { 16 + ox, 17 + oy, 168 + ox, 129 + oy};
  110. _rcInner = rc;
  111. _cxMon = ox;
  112. _cyMon = oy;
  113. }
  114. else
  115. {
  116. _rcInner = _rcOuter;
  117. }
  118. HDC hdcTemp = GetDC(_hwndPrev);
  119. if (hdcTemp)
  120. {
  121. HBITMAP hbmMem = CreateCompatibleBitmap(hdcTemp, RECTWIDTH(_rcOuter), RECTHEIGHT(_rcOuter));
  122. if (hbmMem)
  123. {
  124. HBITMAP hbmOld = (HBITMAP) SelectObject(_hdcMem, hbmMem);
  125. DeleteObject(hbmOld);
  126. }
  127. else
  128. hr = E_FAIL;
  129. ReleaseDC(_hwndPrev, hdcTemp);
  130. }
  131. else
  132. hr = E_FAIL;
  133. if (dwFlags & TMPREV_SHOWBKGND)
  134. {
  135. _fShowBack = TRUE;
  136. }
  137. _fShowVS = dwFlags & TMPREV_SHOWVS;
  138. _fOnlyActiveWindow = _fShowIcons = dwFlags & TMPREV_SHOWICONS;
  139. DEBUG_CODE(TraceMsg(TF_THEMEUI_PERF, "CPreviewTheme::CreatePreview() returned %#08lx. Time=%lums", hr, DebugStopWatch()));
  140. if (SUCCEEDED(hr))
  141. hr = UpdatePreview(pPropertyBag);
  142. }
  143. return hr;
  144. }
  145. //===========================
  146. // *** IUnknown Interface ***
  147. //===========================
  148. ULONG CPreviewTheme::AddRef()
  149. {
  150. return InterlockedIncrement(&m_cRef);
  151. }
  152. ULONG CPreviewTheme::Release()
  153. {
  154. if (InterlockedDecrement(&m_cRef))
  155. return m_cRef;
  156. delete this;
  157. return 0;
  158. }
  159. HRESULT CPreviewTheme::QueryInterface(REFIID riid, void **ppvObj)
  160. {
  161. static const QITAB qit[] =
  162. {
  163. QITABENT(CPreviewTheme, IObjectWithSite),
  164. QITABENT(CPreviewTheme, IThemePreview),
  165. { 0 },
  166. };
  167. return QISearch(this, qit, riid, ppvObj);
  168. }
  169. //===========================
  170. // *** Class Methods ***
  171. //===========================
  172. CPreviewTheme::CPreviewTheme() : m_cRef(1)
  173. {
  174. DllAddRef();
  175. // This needs to be allocated in Zero Inited Memory.
  176. // Assert that all Member Variables are inited to Zero.
  177. ASSERT(!m_pTheme);
  178. ASSERT(!m_pScheme);
  179. ASSERT(!m_pStyle);
  180. ASSERT(!m_pSize);
  181. ASSERT(!_hwndPrev);
  182. }
  183. HRESULT CPreviewTheme::_Init(void)
  184. {
  185. HRESULT hr = S_OK;
  186. _RegisterThemePreviewClass(HINST_THISDLL);
  187. HDC hdc = GetDC(NULL);
  188. if (hdc)
  189. {
  190. _hdcMem = CreateCompatibleDC(hdc);
  191. ReleaseDC(NULL, hdc);
  192. }
  193. else
  194. hr = E_FAIL;
  195. if (_hdcMem)
  196. {
  197. _hbmMon = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_MONITOR));
  198. if (_hbmMon)
  199. {
  200. if (LoadString(HINST_THISDLL, IDS_NONE, _szNone, ARRAYSIZE(_szNone)) == 0)
  201. hr = E_FAIL;
  202. }
  203. else
  204. hr = E_FAIL;
  205. if (SUCCEEDED(hr))
  206. hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&_pThumb);
  207. }
  208. else
  209. hr = E_FAIL;
  210. if (FAILED(hr))
  211. {
  212. if (_hbmMon)
  213. {
  214. DeleteObject(_hbmMon);
  215. _hbmMon = NULL;
  216. }
  217. if (_hdcMem)
  218. {
  219. DeleteDC(_hdcMem);
  220. _hdcMem = NULL;
  221. }
  222. }
  223. return hr;
  224. }
  225. CPreviewTheme::~CPreviewTheme()
  226. {
  227. if (_hwndPrev && IsWindow(_hwndPrev))
  228. {
  229. DestroyWindow(_hwndPrev);
  230. _hwndPrev = NULL;
  231. }
  232. if (_hbmMon)
  233. {
  234. DeleteObject(_hbmMon);
  235. _hbmMon = NULL;
  236. }
  237. if (_hbmBack)
  238. {
  239. DeleteObject(_hbmBack);
  240. _hbmBack = NULL;
  241. }
  242. if (_hbrBack)
  243. {
  244. DeleteObject(_hbrBack);
  245. _hbrBack = NULL;
  246. }
  247. if (_hbmVS)
  248. {
  249. DeleteObject(_hbmVS);
  250. }
  251. if (_hdcMem)
  252. {
  253. DeleteDC(_hdcMem);
  254. _hpalMem = NULL;
  255. _hdcMem = NULL;
  256. }
  257. if (_pActiveDesk)
  258. {
  259. _pActiveDesk->Release();
  260. }
  261. for (int i = 0; i < MAX_PREVIEW_ICONS; i++)
  262. {
  263. if (_iconList[i].hicon)
  264. {
  265. DestroyIcon(_iconList[i].hicon);
  266. }
  267. }
  268. ATOMICRELEASE(m_pTheme);
  269. ATOMICRELEASE(m_pScheme);
  270. ATOMICRELEASE(m_pStyle);
  271. ATOMICRELEASE(m_pSize);
  272. ATOMICRELEASE(_pThumb);
  273. DllRelease();
  274. }
  275. LRESULT CALLBACK CPreviewTheme::ThemePreviewWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  276. {
  277. CPreviewTheme * pThis = (CPreviewTheme *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  278. if (pThis)
  279. return pThis->_ThemePreviewWndProc(hWnd, wMsg, wParam, lParam);
  280. return DefWindowProc(hWnd, wMsg, wParam, lParam);
  281. }
  282. LRESULT CPreviewTheme::_ThemePreviewWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  283. {
  284. switch(wMsg)
  285. {
  286. case WM_CREATE:
  287. break;
  288. case WM_DESTROY:
  289. {
  290. MSG msg;
  291. while (PeekMessage(&msg, hWnd, WM_HTML_BITMAP, WM_ASYNC_BITMAP, PM_REMOVE))
  292. {
  293. if ( msg.lParam )
  294. {
  295. if (msg.message == WM_ASYNC_BITMAP)
  296. {
  297. // clean up this useless crap
  298. DeleteObject(((PASYNCWALLPARAM)(msg.lParam))->hbmp);
  299. LocalFree((PASYNCWALLPARAM)(msg.lParam));
  300. }
  301. else // WM_HTML_BITMAP
  302. DeleteObject((HBITMAP)msg.lParam);
  303. }
  304. }
  305. }
  306. break;
  307. case WM_PALETTECHANGED:
  308. break;
  309. case WM_QUERYNEWPALETTE:
  310. break;
  311. case WM_HTML_BITMAP:
  312. {
  313. // may come through with NULL if the image extraction failed....
  314. if (wParam == _dwWallpaperID && lParam)
  315. {
  316. _fHTMLBitmap = TRUE;
  317. _iTileMode = _iNewTileMode;
  318. _putBackgroundBitmap((HBITMAP)lParam);
  319. // Take ownership of bitmap
  320. return 1;
  321. }
  322. // Bitmap for something no longer selected
  323. return 0;
  324. }
  325. case WM_ASYNC_BITMAP:
  326. if (lParam)
  327. {
  328. PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) lParam;
  329. ASSERT(pawp->hbmp);
  330. if (pawp->id == _dwWallpaperID)
  331. {
  332. _fHTMLBitmap = FALSE;
  333. _iTileMode = _iNewTileMode;
  334. _putBackgroundBitmap(pawp->hbmp);
  335. }
  336. else
  337. {
  338. // clean up this useless crap
  339. DeleteObject(pawp->hbmp);
  340. LocalFree(pawp);
  341. }
  342. }
  343. break;
  344. case WM_PAINT:
  345. {
  346. PAINTSTRUCT ps;
  347. BeginPaint(hWnd, &ps);
  348. _Paint(ps.hdc);
  349. EndPaint(hWnd, &ps);
  350. }
  351. return 0;
  352. case WM_ERASEBKGND:
  353. _Paint((HDC)wParam);
  354. return 1;
  355. }
  356. return DefWindowProc(hWnd,wMsg,wParam,lParam);
  357. }
  358. BOOL CPreviewTheme::_RegisterThemePreviewClass(HINSTANCE hInst)
  359. {
  360. WNDCLASS wc;
  361. if (!GetClassInfo(hInst, THEMEPREV_CLASS, &wc)) {
  362. wc.style = 0;
  363. wc.lpfnWndProc = CPreviewTheme::ThemePreviewWndProc;
  364. wc.cbClsExtra = 0;
  365. wc.cbWndExtra = 0;
  366. wc.hInstance = hInst;
  367. wc.hIcon = NULL;
  368. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  369. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  370. wc.lpszMenuName = NULL;
  371. wc.lpszClassName = THEMEPREV_CLASS;
  372. if (!RegisterClass(&wc))
  373. return FALSE;
  374. }
  375. return TRUE;
  376. }
  377. HRESULT CPreviewTheme::_putIcons(IPropertyBag* pPropertyBag)
  378. {
  379. HRESULT hr;
  380. for (int i = 0; i < MAX_PREVIEW_ICONS; i++)
  381. {
  382. if (_iconList[i].hicon)
  383. {
  384. DestroyIcon(_iconList[i].hicon);
  385. }
  386. WCHAR szIcon[MAX_PATH];
  387. hr = SHPropertyBag_ReadStr(pPropertyBag, s_Icons[i], szIcon, ARRAYSIZE(szIcon));
  388. if (SUCCEEDED(hr))
  389. {
  390. WCHAR szIconModule[MAX_PATH];
  391. SHExpandEnvironmentStrings(szIcon, szIconModule, ARRAYSIZE(szIconModule));
  392. int iIndex = PathParseIconLocation(szIconModule);
  393. ExtractIconEx(szIconModule, iIndex, &_iconList[i].hicon, NULL, 1);
  394. }
  395. }
  396. _fMemIsDirty = TRUE;
  397. InvalidateRect(_hwndPrev, &_rcInner, FALSE);
  398. return S_OK;
  399. }
  400. HRESULT CPreviewTheme::_putVisualStyle(LPCWSTR pszVSPath, LPCWSTR pszVSColor, LPCWSTR pszVSSize, SYSTEMMETRICSALL* psysMet)
  401. {
  402. HRESULT hr = E_FAIL;
  403. HBITMAP hbmVS = NULL;
  404. HBITMAP hbmOldVS = NULL;
  405. HDC hdcVS = NULL;
  406. if (!pszVSPath || !*pszVSPath)
  407. {
  408. HDC hdcTemp = GetDC(_hwndPrev);
  409. if (hdcTemp)
  410. {
  411. hdcVS = CreateCompatibleDC(hdcTemp);
  412. hbmVS = CreateCompatibleBitmap(hdcTemp, RECTWIDTH(_rcInner), RECTHEIGHT(_rcInner));
  413. hbmOldVS = (HBITMAP)SelectObject(hdcVS, hbmVS);
  414. if (hdcVS && hbmVS)
  415. {
  416. RECT rcVS;
  417. rcVS.left = 0;
  418. rcVS.right = RECTWIDTH(_rcInner) - (_fShowIcons ? 100 : 8);
  419. rcVS.top = 0;
  420. rcVS.bottom = RECTHEIGHT(_rcInner) - (_fShowIcons ? 50 : 8);
  421. // Create everyone including globals
  422. HDC hdcVStemp = CreateCompatibleDC(hdcTemp);
  423. HBITMAP hbmVStemp = CreateCompatibleBitmap(hdcTemp, RECTWIDTH(rcVS), RECTHEIGHT(rcVS));
  424. HBITMAP hbmOldVStemp = (HBITMAP) SelectObject(hdcVStemp, hbmVStemp);
  425. if (hdcVStemp && hbmVStemp)
  426. {
  427. if (_fRTL)
  428. {
  429. SetLayout(hdcVStemp, LAYOUT_RTL);
  430. SetLayout(hdcVS, LAYOUT_RTL);
  431. }
  432. HBRUSH hbr = CreateSolidBrush(RGB(255, 255, 0));
  433. if (hbr)
  434. {
  435. FillRect(hdcVStemp, &rcVS, hbr);
  436. RECT rcTemp = {0, 0, RECTWIDTH(_rcInner), RECTHEIGHT(_rcInner)};
  437. FillRect(hdcVS, &rcTemp, hbr);
  438. DeleteObject(hbr);
  439. }
  440. // Render image at full size
  441. hr = DrawAppearance(hdcVStemp, &rcVS, psysMet, _fOnlyActiveWindow, _fRTL);
  442. // Shrink image to fit on "monitor"
  443. int iX = _rcInner.left + (_fShowIcons ? 10 : RECTWIDTH(_rcInner) - RECTWIDTH(rcVS));
  444. BitBlt(hdcVS, iX, _rcInner.top, RECTWIDTH(rcVS), RECTHEIGHT(rcVS),
  445. hdcVStemp, rcVS.left, rcVS.top, SRCCOPY);
  446. }
  447. // Free temporary variables and store off globals
  448. if (hdcVStemp)
  449. {
  450. SelectObject(hdcVStemp, hbmOldVStemp);
  451. DeleteDC(hdcVStemp);
  452. }
  453. if (hbmVStemp)
  454. {
  455. DeleteObject(hbmVStemp);
  456. }
  457. }
  458. ReleaseDC(_hwndPrev, hdcTemp);
  459. }
  460. else
  461. hr = E_OUTOFMEMORY;
  462. }
  463. else
  464. {
  465. hr = S_OK;
  466. }
  467. if (SUCCEEDED(hr))
  468. {
  469. if (_hbmVS)
  470. {
  471. DeleteObject(_hbmVS);
  472. }
  473. _hbmVS = hbmVS;
  474. hbmVS = NULL;
  475. _fMemIsDirty = TRUE;
  476. InvalidateRect(_hwndPrev, &_rcInner, FALSE);
  477. }
  478. if (hdcVS)
  479. {
  480. if (hbmOldVS)
  481. {
  482. SelectObject(hdcVS, hbmOldVS);
  483. }
  484. DeleteDC(hdcVS);
  485. }
  486. if (hbmVS)
  487. {
  488. DeleteObject(hbmVS);
  489. }
  490. return hr;
  491. }
  492. HRESULT CPreviewTheme::_putBackgroundBitmap(HBITMAP hbm)
  493. {
  494. if (_hbmBack)
  495. {
  496. DeleteObject(_hbmBack);
  497. _hbmBack = NULL;
  498. }
  499. if (_hpalMem)
  500. {
  501. DeleteObject(_hpalMem);
  502. _hpalMem = NULL;
  503. }
  504. _hbmBack = hbm;
  505. if (_hbmBack)
  506. {
  507. BITMAP bm;
  508. GetObject(_hbmBack, sizeof(bm), &bm);
  509. if (GetDeviceCaps(_hdcMem, RASTERCAPS) & RC_PALETTE)
  510. {
  511. if (bm.bmBitsPixel * bm.bmPlanes > 8)
  512. _hpalMem = CreateHalftonePalette(_hdcMem);
  513. else if (bm.bmBitsPixel * bm.bmPlanes == 8)
  514. _PaletteFromDS(_hdcMem, &_hpalMem);
  515. else
  516. _hpalMem = NULL; //!!! assume 1 or 4bpp images dont have palettes
  517. }
  518. }
  519. _fMemIsDirty = TRUE;
  520. InvalidateRect(_hwndPrev, &_rcInner, FALSE);
  521. return S_OK;
  522. }
  523. HRESULT CPreviewTheme::_putBackground(BSTR bstrBackground, BOOL fPattern, int iTileMode)
  524. {
  525. if (fPattern)
  526. {
  527. TCHAR szBuf[MAX_PATH];
  528. // get rid of old brush if there was one
  529. if (_hbrBack)
  530. DeleteObject(_hbrBack);
  531. if (bstrBackground && lstrcmpi(bstrBackground, _szNone))
  532. {
  533. WORD patbits[CXYDESKPATTERN] = {0, 0, 0, 0, 0, 0, 0, 0};
  534. if (GetPrivateProfileString(TEXT("patterns"), bstrBackground, TEXT(""),
  535. szBuf, ARRAYSIZE(szBuf), TEXT("control.ini")))
  536. {
  537. _ReadPattern(szBuf, patbits);
  538. }
  539. HBITMAP hbmTemp = CreateBitmap(8, 8, 1, 1, patbits);
  540. if (hbmTemp)
  541. {
  542. _hbrBack = CreatePatternBrush(hbmTemp);
  543. DeleteObject(hbmTemp);
  544. }
  545. }
  546. else
  547. {
  548. _hbrBack = CreateSolidBrush(_systemMetricsAll.schemeData.rgb[COLOR_BACKGROUND]);
  549. }
  550. if (!_hbrBack)
  551. _hbrBack = (HBRUSH) GetStockObject(BLACK_BRUSH);
  552. _fMemIsDirty = TRUE;
  553. InvalidateRect(_hwndPrev, &_rcInner, FALSE);
  554. }
  555. else
  556. {
  557. _iNewTileMode = iTileMode;
  558. return _GetWallpaperAsync(bstrBackground);
  559. }
  560. return S_OK;
  561. }
  562. /*-------------------------------------------------------------
  563. ** given a pattern string from an ini file, return the pattern
  564. ** in a binary (ie useful) form.
  565. **-------------------------------------------------------------*/
  566. HRESULT CPreviewTheme::_ReadPattern(LPTSTR lpStr, WORD FAR *patbits)
  567. {
  568. short i, val;
  569. /* Get eight groups of numbers seprated by non-numeric characters. */
  570. for (i = 0; i < CXYDESKPATTERN; i++)
  571. {
  572. val = 0;
  573. if (*lpStr != TEXT('\0'))
  574. {
  575. /* Skip over any non-numeric characters. */
  576. while (!(*lpStr >= TEXT('0') && *lpStr <= TEXT('9')))
  577. lpStr++;
  578. /* Get the next series of digits. */
  579. while (*lpStr >= TEXT('0') && *lpStr <= TEXT('9'))
  580. val = val*10 + *lpStr++ - TEXT('0');
  581. }
  582. patbits[i] = val;
  583. }
  584. return S_OK;
  585. }
  586. /*----------------------------------------------------------------------------*\
  587. \*----------------------------------------------------------------------------*/
  588. HRESULT CPreviewTheme::_PaletteFromDS(HDC hdc, HPALETTE* phPalette)
  589. {
  590. DWORD adw[257];
  591. int i,n;
  592. n = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)&adw[1]);
  593. adw[0] = MAKELONG(0x300, n);
  594. for (i=1; i<=n; i++)
  595. adw[i] = RGB(GetBValue(adw[i]),GetGValue(adw[i]),GetRValue(adw[i]));
  596. *phPalette = (n == 0) ? NULL : CreatePalette((LPLOGPALETTE)&adw[0]);
  597. return S_OK;
  598. }
  599. HRESULT CPreviewTheme::_DrawMonitor(HDC hdc)
  600. {
  601. HBITMAP hbmT;
  602. HDC hdcMon;
  603. BITMAP bmMon;
  604. if (_hbmMon == NULL)
  605. {
  606. return E_OUTOFMEMORY;
  607. }
  608. //
  609. // convert the "base" of the monitor to the right color.
  610. //
  611. // the lower left of the bitmap has a transparent color
  612. // we fixup using FloodFill
  613. //
  614. hdcMon = CreateCompatibleDC(NULL);
  615. if (hdcMon)
  616. {
  617. hbmT = (HBITMAP) SelectObject(hdcMon, _hbmMon);
  618. GetObject(_hbmMon, sizeof(bmMon), &bmMon);
  619. FillRect(hdc, &_rcOuter, GetSysColorBrush(COLOR_3DFACE));
  620. DrawThemeParentBackground(_hwndPrev, hdc, NULL);
  621. TransparentBlt(hdc, _rcOuter.left + _cxMon, _rcOuter.top + _cyMon, bmMon.bmWidth, bmMon.bmHeight,
  622. hdcMon, 0, 0, bmMon.bmWidth, bmMon.bmHeight, RGB(255, 0, 255));
  623. // clean up after ourselves
  624. SelectObject(hdcMon, hbmT);
  625. DeleteDC(hdcMon);
  626. }
  627. return S_OK;
  628. }
  629. HRESULT CPreviewTheme::_DrawBackground(HDC hdc)
  630. {
  631. // Draw Pattern first
  632. if (_hbrBack)
  633. {
  634. COLORREF clrOldText = SetTextColor(hdc, GetSysColor(COLOR_BACKGROUND));
  635. COLORREF clrOldBk = SetBkColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  636. HBRUSH hbr = (HBRUSH) SelectObject(hdc, _hbrBack);
  637. PatBlt(hdc, _rcInner.left, _rcInner.top, RECTWIDTH(_rcInner), RECTHEIGHT(_rcInner), PATCOPY);
  638. SelectObject(hdc, hbr);
  639. SetTextColor(hdc, clrOldText);
  640. SetBkColor(hdc, clrOldBk);
  641. }
  642. /// Start Draw Wall Paper
  643. if (_hbmBack && _fShowBack)
  644. {
  645. HDC hdcBack = CreateCompatibleDC(hdc);
  646. if (hdcBack)
  647. {
  648. HBITMAP hbmOldBack = (HBITMAP)SelectObject(hdcBack, _hbmBack);
  649. BITMAP bm;
  650. GetObject(_hbmBack, sizeof(bm), &bm);
  651. int dxBack = MulDiv(bm.bmWidth, RECTWIDTH(_rcInner), GetDeviceCaps(hdc, HORZRES));
  652. int dyBack = MulDiv(bm.bmHeight, RECTHEIGHT(_rcInner), GetDeviceCaps(hdc, VERTRES));
  653. if (dxBack < 1) dxBack = 1;
  654. if (dyBack < 1) dyBack = 1;
  655. if (_hpalMem)
  656. {
  657. SelectPalette(hdc, _hpalMem, TRUE);
  658. RealizePalette(hdc);
  659. }
  660. IntersectClipRect(hdc, _rcInner.left, _rcInner.top, _rcInner.right, _rcInner.bottom);
  661. SetStretchBltMode(hdc, COLORONCOLOR);
  662. if ((_iTileMode == WPSTYLE_TILE) && (!_fHTMLBitmap))
  663. {
  664. int i;
  665. StretchBlt(hdc, _rcInner.left, _rcInner.top, dxBack, dyBack,
  666. hdcBack, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  667. for (i = _rcInner.left+dxBack; i < (_rcInner.left + RECTWIDTH(_rcInner)); i+= dxBack)
  668. BitBlt(hdc, i, _rcInner.top, dxBack, dyBack, hdc, _rcInner.left, _rcInner.top, SRCCOPY);
  669. for (i = _rcInner.top; i < (_rcInner.top + RECTHEIGHT(_rcInner)); i += dyBack)
  670. BitBlt(hdc, _rcInner.left, i, RECTWIDTH(_rcInner), dyBack, hdc, _rcInner.left, _rcInner.top, SRCCOPY);
  671. }
  672. else
  673. {
  674. //We want to stretch the Bitmap to the preview monitor size ONLY for new platforms.
  675. if ((_iTileMode == WPSTYLE_STRETCH) || (_fHTMLBitmap))
  676. {
  677. //Stretch the bitmap to the whole preview monitor.
  678. dxBack = RECTWIDTH(_rcInner);
  679. dyBack = RECTHEIGHT(_rcInner);
  680. }
  681. //Center the bitmap in the preview monitor
  682. StretchBlt(hdc, _rcInner.left + (RECTWIDTH(_rcInner) - dxBack)/2, _rcInner.top + (RECTHEIGHT(_rcInner) - dyBack)/2,
  683. dxBack, dyBack, hdcBack, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  684. }
  685. // restore dc
  686. SelectPalette(hdc, (HPALETTE) GetStockObject(DEFAULT_PALETTE), TRUE);
  687. SelectClipRgn(hdc, NULL);
  688. SelectObject(hdcBack, hbmOldBack);
  689. DeleteDC(hdcBack);
  690. }
  691. }
  692. return S_OK;
  693. }
  694. HRESULT CPreviewTheme::_DrawVisualStyle(HDC hdc)
  695. {
  696. if (_hbmVS)
  697. {
  698. HDC hdcVS = CreateCompatibleDC(hdc);
  699. if (hdcVS)
  700. {
  701. HBITMAP hbmOldVS = (HBITMAP)SelectObject(hdcVS, _hbmVS);
  702. TransparentBlt(hdc, _rcInner.left, _rcInner.top, RECTWIDTH(_rcInner), RECTHEIGHT(_rcInner), hdcVS, 0, 0, RECTWIDTH(_rcInner), RECTHEIGHT(_rcInner), RGB(255, 255, 0));
  703. SelectObject(hdcVS, hbmOldVS);
  704. DeleteDC(hdcVS);
  705. }
  706. }
  707. else
  708. {
  709. RECT rc;
  710. rc.left = _fShowIcons ? 20 : 8;
  711. rc.right = RECTWIDTH(_rcInner) - (_fShowIcons ? 100 : 8);
  712. rc.top = _fShowIcons ? 10 : 8;
  713. rc.bottom = RECTHEIGHT(_rcInner) - (_fShowIcons ? 60 : 20);
  714. DrawNCPreview(hdc, NCPREV_ACTIVEWINDOW | (_fOnlyActiveWindow ? 0 : NCPREV_MESSAGEBOX | NCPREV_INACTIVEWINDOW) | (_fRTL ? NCPREV_RTL : 0) , &rc, _szVSPath, _szVSColor, _szVSSize, &(_systemMetricsAll.schemeData.ncm), (_systemMetricsAll.schemeData.rgb));
  715. }
  716. return S_OK;
  717. }
  718. HRESULT CPreviewTheme::_DrawIcons(HDC hdc)
  719. {
  720. int y = RECTHEIGHT(_rcInner) - _systemMetricsAll.nIcon - 8;
  721. int x = RECTWIDTH(_rcInner) - _systemMetricsAll.nIcon - 20;
  722. DrawIcon(hdc, x, y, _iconList[3].hicon);
  723. return S_OK;
  724. }
  725. HRESULT CPreviewTheme::_Paint(HDC hdc)
  726. {
  727. HPALETTE hpalOld = NULL;
  728. if (_fMemIsDirty)
  729. {
  730. if (_fRTL)
  731. {
  732. SetLayout(_hdcMem, LAYOUT_RTL);
  733. }
  734. // Rebuild Back Buffer
  735. if (_fShowMon)
  736. _DrawMonitor(_hdcMem);
  737. // Always draw the background, the Background switch turns the background
  738. // image on/off
  739. _DrawBackground(_hdcMem);
  740. if (_fShowIcons)
  741. _DrawIcons(_hdcMem);
  742. if (_fShowVS)
  743. _DrawVisualStyle(_hdcMem);
  744. _fMemIsDirty = FALSE;
  745. }
  746. if (_hdcMem)
  747. {
  748. if (_hpalMem)
  749. {
  750. hpalOld = SelectPalette(hdc, _hpalMem, FALSE);
  751. RealizePalette(hdc);
  752. }
  753. if (_fRTL)
  754. {
  755. SetLayout(hdc, LAYOUT_RTL);
  756. }
  757. BitBlt(hdc, _rcOuter.left, _rcOuter.top, RECTWIDTH(_rcOuter), RECTHEIGHT(_rcOuter), _hdcMem, 0, 0, SRCCOPY);
  758. if (_hpalMem)
  759. {
  760. SelectPalette(hdc, hpalOld, TRUE);
  761. RealizePalette(hdc);
  762. }
  763. }
  764. return S_OK;
  765. }
  766. DWORD CALLBACK UpdateWallProc(LPVOID pv)
  767. {
  768. ASSERT(pv);
  769. if (pv)
  770. {
  771. PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) pv;
  772. pawp->hbmp = (HBITMAP)LoadImage(NULL, pawp->szFile,
  773. IMAGE_BITMAP, 0, 0,
  774. LR_LOADFROMFILE|LR_CREATEDIBSECTION);
  775. if (pawp->hbmp)
  776. {
  777. // if all is good, then the window will handle cleaning up
  778. if (IsWindow(pawp->hwnd) && PostMessage(pawp->hwnd, WM_ASYNC_BITMAP, 0, (LPARAM)pawp))
  779. return TRUE;
  780. DeleteObject(pawp->hbmp);
  781. }
  782. LocalFree(pawp);
  783. }
  784. return TRUE;
  785. }
  786. const GUID CLSID_HtmlThumbnailExtractor = {0xeab841a0, 0x9550, 0x11cf, 0x8c, 0x16, 0x0, 0x80, 0x5f, 0x14, 0x8, 0xf3};
  787. DWORD CALLBACK UpdateWallProcHTML(LPVOID pv)
  788. {
  789. if (SUCCEEDED(CoInitialize(NULL)))
  790. {
  791. ASSERT(pv);
  792. if (pv)
  793. {
  794. PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) pv;
  795. IPersistFile *ppf;
  796. HRESULT hr = CoCreateInstance(CLSID_HtmlThumbnailExtractor, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPersistFile, &ppf));
  797. if (SUCCEEDED(hr))
  798. {
  799. hr = ppf->Load(pawp->szFile, STGM_READ);
  800. if (SUCCEEDED(hr))
  801. {
  802. IExtractImage *pei= NULL;
  803. hr = ppf->QueryInterface(IID_PPV_ARG(IExtractImage, &pei));
  804. if (SUCCEEDED(hr))
  805. {
  806. DWORD dwPriority = 0;
  807. DWORD dwFlags = IEIFLAG_SCREEN | IEIFLAG_OFFLINE;
  808. WCHAR szLocation[MAX_PATH];
  809. HDC hdc = GetDC(NULL);
  810. SIZEL rgSize = {GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES)};
  811. ReleaseDC(NULL, hdc);
  812. hr = pei->GetLocation(szLocation, ARRAYSIZE(szLocation), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags);
  813. if (SUCCEEDED(hr))
  814. {
  815. HBITMAP hbm;
  816. hr = pei->Extract(&hbm);
  817. if (SUCCEEDED(hr))
  818. {
  819. if (!SendMessage(pawp->hwnd, WM_HTML_BITMAP, pawp->id, (LPARAM)hbm))
  820. {
  821. DeleteObject(hbm);
  822. }
  823. }
  824. }
  825. pei->Release();
  826. }
  827. }
  828. ppf->Release();
  829. }
  830. LocalFree(pawp);
  831. }
  832. CoUninitialize();
  833. }
  834. return TRUE;
  835. }
  836. //
  837. // Determines if the wallpaper can be supported in non-active desktop mode.
  838. //
  839. BOOL CPreviewTheme::_IsNormalWallpaper(LPCWSTR pszFileName)
  840. {
  841. BOOL fRet = TRUE;
  842. if (pszFileName[0] == TEXT('\0'))
  843. {
  844. fRet = TRUE;
  845. }
  846. else
  847. {
  848. LPTSTR pszExt = PathFindExtension(pszFileName);
  849. //Check for specific files that can be shown only in ActiveDesktop mode!
  850. if((lstrcmpi(pszExt, TEXT(".GIF")) == 0) ||
  851. (lstrcmpi(pszExt, TEXT(".gif")) == 0) || // 368690: Strange, but we must compare 'i' in both caps and lower case.
  852. (lstrcmpi(pszExt, TEXT(".JPG")) == 0) ||
  853. (lstrcmpi(pszExt, TEXT(".JPE")) == 0) ||
  854. (lstrcmpi(pszExt, TEXT(".JPEG")) == 0) ||
  855. (lstrcmpi(pszExt, TEXT(".PNG")) == 0) ||
  856. (lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  857. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  858. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  859. return FALSE;
  860. //Everything else (including *.BMP files) are "normal" wallpapers
  861. }
  862. return fRet;
  863. }
  864. //
  865. // Determines if the wallpaper is a picture (vs. HTML).
  866. //
  867. BOOL CPreviewTheme::_IsWallpaperPicture(LPCWSTR pszWallpaper)
  868. {
  869. BOOL fRet = TRUE;
  870. if (pszWallpaper[0] == TEXT('\0'))
  871. {
  872. //
  873. // Empty wallpapers count as empty pictures.
  874. //
  875. fRet = TRUE;
  876. }
  877. else
  878. {
  879. LPTSTR pszExt = PathFindExtension(pszWallpaper);
  880. if ((lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  881. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  882. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  883. {
  884. fRet = FALSE;
  885. }
  886. }
  887. return fRet;
  888. }
  889. HRESULT CPreviewTheme::_LoadWallpaperAsync(LPCWSTR pszFile, DWORD dwID, BOOL bHTML)
  890. {
  891. PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) LocalAlloc(LPTR, SIZEOF(ASYNCWALLPARAM));
  892. if (pawp)
  893. {
  894. pawp->hwnd = _hwndPrev;
  895. pawp->id = dwID;
  896. StrCpyN(pawp->szFile, pszFile, SIZECHARS(pawp->szFile));
  897. if (bHTML)
  898. {
  899. if (!SHQueueUserWorkItem(UpdateWallProcHTML, pawp, 0, (DWORD_PTR)0, (DWORD_PTR *)NULL, NULL, 0))
  900. LocalFree(pawp);
  901. }
  902. else
  903. {
  904. if (!SHQueueUserWorkItem(UpdateWallProc, pawp, 0, (DWORD_PTR)0, (DWORD_PTR *)NULL, NULL, 0))
  905. LocalFree(pawp);
  906. }
  907. }
  908. return S_OK;
  909. }
  910. HRESULT CPreviewTheme::_GetWallpaperAsync(LPWSTR psz)
  911. {
  912. HRESULT hr = S_OK;
  913. WCHAR wszWallpaper[INTERNET_MAX_URL_LENGTH];
  914. LPWSTR pszWallpaper = psz;
  915. _dwWallpaperID++;
  916. if (*pszWallpaper && lstrcmpi(pszWallpaper, _szNone))
  917. {
  918. if (_IsNormalWallpaper(pszWallpaper))
  919. {
  920. _LoadWallpaperAsync(pszWallpaper, _dwWallpaperID, FALSE);
  921. }
  922. else
  923. {
  924. if(_IsWallpaperPicture(pszWallpaper))
  925. {
  926. pszWallpaper = wszWallpaper;
  927. // This is a picture (GIF, JPG etc.,)
  928. // We need to generate a small HTML file that has this picture
  929. // as the background image.
  930. //
  931. // Compute the filename for the Temporary HTML file.
  932. //
  933. GetTempPath(ARRAYSIZE(wszWallpaper), wszWallpaper);
  934. lstrcat(wszWallpaper, PREVIEW_PICTURE_FILENAME);
  935. //
  936. // Generate the preview picture html file.
  937. //
  938. if (!_pActiveDesk)
  939. {
  940. hr = _GetActiveDesktop(&_pActiveDesk);
  941. }
  942. if (SUCCEEDED(hr))
  943. {
  944. _pActiveDesk->SetWallpaper(psz, 0);
  945. WALLPAPEROPT wpo = { sizeof(WALLPAPEROPT) };
  946. wpo.dwStyle = _iNewTileMode;
  947. _pActiveDesk->SetWallpaperOptions(&wpo, 0);
  948. _pActiveDesk->GenerateDesktopItemHtml(wszWallpaper, NULL, 0);
  949. }
  950. }
  951. _LoadWallpaperAsync(pszWallpaper, _dwWallpaperID, TRUE);
  952. }
  953. }
  954. else
  955. {
  956. _putBackgroundBitmap(NULL);
  957. }
  958. return hr;
  959. }
  960. HRESULT CPreviewTheme::_GetActiveDesktop(IActiveDesktop ** ppActiveDesktop)
  961. {
  962. HRESULT hr = S_OK;
  963. if (!*ppActiveDesktop)
  964. {
  965. IActiveDesktopP * piadp;
  966. if (SUCCEEDED(hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IActiveDesktopP, &piadp)) ))
  967. {
  968. WCHAR wszScheme[MAX_PATH];
  969. DWORD dwcch = ARRAYSIZE(wszScheme);
  970. // Get the global "edit" scheme and set ourselves us to read from and edit that scheme
  971. if (SUCCEEDED(piadp->GetScheme(wszScheme, &dwcch, SCHEME_GLOBAL | SCHEME_EDIT)))
  972. {
  973. piadp->SetScheme(wszScheme, SCHEME_LOCAL);
  974. }
  975. hr = piadp->QueryInterface(IID_PPV_ARG(IActiveDesktop, ppActiveDesktop));
  976. piadp->Release();
  977. }
  978. }
  979. else
  980. {
  981. (*ppActiveDesktop)->AddRef();
  982. }
  983. return hr;
  984. }
  985. HRESULT CThemePreview_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
  986. {
  987. HRESULT hr = E_INVALIDARG;
  988. if (punkOuter)
  989. {
  990. return CLASS_E_NOAGGREGATION;
  991. }
  992. if (ppvObj)
  993. {
  994. CPreviewTheme * pObject = new CPreviewTheme();
  995. *ppvObj = NULL;
  996. if (pObject)
  997. {
  998. hr = pObject->_Init();
  999. if (SUCCEEDED(hr))
  1000. {
  1001. hr = pObject->QueryInterface(riid, ppvObj);
  1002. }
  1003. pObject->Release();
  1004. }
  1005. else
  1006. {
  1007. hr = E_OUTOFMEMORY;
  1008. }
  1009. }
  1010. return hr;
  1011. }