Leaked source code of windows server 2003
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.

1381 lines
43 KiB

  1. #include "precomp.h"
  2. #include "winuser.h"
  3. #include <shdguid.h> // For CLSID_CDeskHtmlProp
  4. #include <shlwapi.h>
  5. #include <shlobj.h>
  6. #include <shlobjp.h>
  7. #include <shlwapip.h>
  8. #include <regapi.h>
  9. #include <ctxdef.h> // hydra stuff
  10. #include <cowsite.h>
  11. #include <theme.h>
  12. #include "cplext.h"
  13. #include "cplp.h"
  14. HWND g_hDlg = NULL;
  15. ///////////////////////////////////////////////////////////////////////////////
  16. // Array defining each page in the sheet
  17. ///////////////////////////////////////////////////////////////////////////////
  18. typedef struct {
  19. int id;
  20. DLGPROC pfnDlgProc;
  21. RESTRICTIONS dwPolicy1;
  22. RESTRICTIONS dwPolicy2;
  23. long nExtensionID; // The page
  24. } PAGEINFO;
  25. PAGEINFO aPageInfo[] = {
  26. { 0, NULL, REST_NODISPLAYAPPEARANCEPAGE, REST_NOTHEMESTAB, PAGE_DISPLAY_THEMES}, // Theme page
  27. { DLG_BACKGROUND, BackgroundDlgProc, REST_NODISPBACKGROUND, (RESTRICTIONS)0, 0}, // Background page
  28. { DLG_SCREENSAVER, NULL, REST_NODISPSCREENSAVEPG, (RESTRICTIONS)0, 0}, // Screen Saver page
  29. { 0, NULL, REST_NODISPLAYAPPEARANCEPAGE, (RESTRICTIONS)0, PAGE_DISPLAY_APPEARANCE}, // Appearance page
  30. { 0, NULL, REST_NODISPSETTINGSPG, (RESTRICTIONS)0, PAGE_DISPLAY_SETTINGS}, // Settings page
  31. };
  32. #define C_PAGES_DESK ARRAYSIZE(aPageInfo)
  33. #define IPI_SETTINGS (C_PAGES_DESK-1) // Index to "Settings" page
  34. #define SZ_WALLPAPER L"Wallpaper"
  35. #define EnableApplyButton(hdlg) PropSheet_Changed(GetParent(hdlg), hdlg)
  36. IThemeUIPages * g_pThemeUI = NULL;
  37. // Local Constant Declarations
  38. static const TCHAR sc_szCoverClass[] = TEXT("DeskSaysNoPeekingItsASurprise");
  39. LRESULT CALLBACK CoverWindowProc( HWND, UINT, WPARAM, LPARAM );
  40. // These are actions that can be passed in the cmdline.
  41. // FORMAT: "/Action:<ActionType>"
  42. #define DESKACTION_NONE 0x00000000
  43. #define DESKACTION_OPENTHEME 0x00000001
  44. #define DESKACTION_OPENMSTHEM 0x00000002
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // Globals
  47. ///////////////////////////////////////////////////////////////////////////////
  48. TCHAR gszDeskCaption[CCH_MAX_STRING];
  49. TCHAR g_szNULL[] = TEXT("");
  50. TCHAR g_szControlIni[] = TEXT("control.ini");
  51. TCHAR g_szPatterns[] = TEXT("patterns") ;
  52. TCHAR g_szNone[CCH_NONE]; // this is the '(None)' string
  53. TCHAR g_szSystemIni[] = TEXT("system.ini");
  54. TCHAR g_szWindows[] = TEXT("Windows");
  55. TCHAR szRegStr_Colors[] = REGSTR_PATH_COLORS;
  56. HDC g_hdcMem = NULL;
  57. HBITMAP g_hbmDefault = NULL;
  58. BOOL g_bMirroredOS = FALSE;
  59. ///////////////////////////////////////////////////////////////////////////////
  60. // Externs
  61. ///////////////////////////////////////////////////////////////////////////////
  62. extern BOOL NEAR PASCAL GetStringFromReg(HKEY hKey,
  63. LPCTSTR lpszSubkey,
  64. LPCTSTR lpszValueName,
  65. LPCTSTR lpszDefault,
  66. LPTSTR lpszValue,
  67. DWORD cchSizeofValueBuff);
  68. //============================================================================================================
  69. // Class
  70. //============================================================================================================
  71. class CDisplayControlPanel : public CObjectWithSite
  72. {
  73. public:
  74. //////////////////////////////////////////////////////
  75. // Public Interfaces
  76. //////////////////////////////////////////////////////
  77. // *** IUnknown ***
  78. virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  79. virtual STDMETHODIMP_(ULONG) AddRef(void);
  80. virtual STDMETHODIMP_(ULONG) Release(void);
  81. void DisplayDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline);
  82. CDisplayControlPanel(void);
  83. virtual ~CDisplayControlPanel(void);
  84. private:
  85. // Private Member Variables
  86. long m_cRef;
  87. HANDLE m_hBackgroundThreads;
  88. void _ShowDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline);
  89. };
  90. /*---------------------------------------------------------
  91. **
  92. **---------------------------------------------------------*/
  93. BOOL NEAR PASCAL CreateGlobals()
  94. {
  95. WNDCLASS wc;
  96. HBITMAP hbm;
  97. HDC hdc;
  98. //
  99. // Check if the mirroring APIs exist on the current
  100. // platform.
  101. //
  102. g_bMirroredOS = IS_MIRRORING_ENABLED();
  103. if( !GetClassInfo( hInstance, sc_szCoverClass, &wc ) )
  104. {
  105. // if two pages put one up, share one dc
  106. wc.style = CS_CLASSDC;
  107. wc.lpfnWndProc = CoverWindowProc;
  108. wc.cbClsExtra = wc.cbWndExtra = 0;
  109. wc.hInstance = hInstance;
  110. wc.hIcon = (HICON)( wc.hCursor = NULL );
  111. // use a real brush since user will try to paint us when we're "hung"
  112. wc.hbrBackground = (HBRUSH) GetStockObject( NULL_BRUSH );
  113. wc.lpszMenuName = NULL;
  114. wc.lpszClassName = sc_szCoverClass;
  115. if( !RegisterClass( &wc ) )
  116. return FALSE;
  117. }
  118. hdc = GetDC(NULL);
  119. g_hdcMem = CreateCompatibleDC(hdc);
  120. ReleaseDC(NULL, hdc);
  121. if (!g_hdcMem)
  122. return FALSE;
  123. hbm = CreateBitmap(1, 1, 1, 1, NULL);
  124. if (hbm)
  125. {
  126. g_hbmDefault = (HBITMAP) SelectObject(g_hdcMem, hbm);
  127. SelectObject(g_hdcMem, g_hbmDefault);
  128. DeleteObject(hbm);
  129. }
  130. LoadString(hInstance, IDS_NONE, g_szNone, ARRAYSIZE(g_szNone));
  131. return TRUE;
  132. }
  133. int DisplaySaveSettings(PVOID pContext, HWND hwnd)
  134. {
  135. int iRet = 0;
  136. if (g_pThemeUI)
  137. {
  138. g_pThemeUI->DisplaySaveSettings(pContext, hwnd, &iRet);
  139. }
  140. return iRet;
  141. }
  142. ///////////////////////////////////////////////////////////////////////////////
  143. //
  144. // InstallScreenSaver
  145. //
  146. // Provides a RUNDLL32-callable routine to install a screen saver
  147. //
  148. ///////////////////////////////////////////////////////////////////////////////
  149. //
  150. // Windows NT:
  151. //
  152. // Thunk ANSI version to the Unicode function
  153. //
  154. void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw );
  155. void WINAPI InstallScreenSaverA( HWND wnd, HINSTANCE inst, LPSTR cmd, int shw )
  156. {
  157. LPWSTR pwszCmd;
  158. int cch;
  159. cch = MultiByteToWideChar( CP_ACP, 0, cmd, -1, NULL, 0);
  160. if (cch == 0)
  161. return;
  162. pwszCmd = (LPWSTR) LocalAlloc( LMEM_FIXED, cch * SIZEOF(TCHAR) );
  163. if (pwszCmd == NULL)
  164. return;
  165. if (0 != MultiByteToWideChar( CP_ACP, 0, cmd, -1, pwszCmd, cch))
  166. {
  167. InstallScreenSaverW(wnd, inst, pwszCmd, shw);
  168. }
  169. LocalFree(pwszCmd);
  170. }
  171. #define REAL_INSTALL_SCREEN_SAVER InstallScreenSaverW
  172. void WINAPI REAL_INSTALL_SCREEN_SAVER( HWND wnd, HINSTANCE inst, LPTSTR cmd, int shw )
  173. {
  174. TCHAR buf[ MAX_PATH ];
  175. int timeout;
  176. StringCchCopy( buf, ARRAYSIZE(buf), cmd );
  177. PathGetShortPath( buf ); // so msscenes doesn't die
  178. WritePrivateProfileString( TEXT("boot"), TEXT("SCRNSAVE.EXE"), buf, TEXT("system.ini") );
  179. SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, TRUE, NULL,
  180. SPIF_UPDATEINIFILE );
  181. // make sure the user has a reasonable timeout set
  182. SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &timeout, 0 );
  183. if( timeout <= 0 )
  184. {
  185. // 15 minutes seems like a nice default
  186. SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, 900, NULL,
  187. SPIF_UPDATEINIFILE );
  188. }
  189. // bring up the screen saver page on our rundll
  190. Control_RunDLLW( wnd, inst, TEXT("DESK.CPL,,1"), shw );
  191. }
  192. /*****************************************************************************\
  193. *
  194. * DeskInitCpl( void )
  195. *
  196. \*****************************************************************************/
  197. BOOL DeskInitCpl(void)
  198. {
  199. InitCommonControls();
  200. CreateGlobals();
  201. return TRUE;
  202. }
  203. HRESULT OpenAdvancedDialog(HWND hDlg, const CLSID * pClsid)
  204. {
  205. HRESULT hr = E_FAIL;
  206. IEnumUnknown * pEnumUnknown;
  207. hr = g_pThemeUI->GetBasePagesEnum(&pEnumUnknown);
  208. if (SUCCEEDED(hr))
  209. {
  210. IUnknown * punk;
  211. hr = IEnumUnknown_FindCLSID(pEnumUnknown, *pClsid, &punk);
  212. if (SUCCEEDED(hr))
  213. {
  214. IBasePropPage * pBasePage;
  215. hr = punk->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePage));
  216. if (SUCCEEDED(hr))
  217. {
  218. IPropertyBag * pPropertyBag;
  219. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  220. if (SUCCEEDED(hr))
  221. {
  222. if (IsEqualCLSID(PPID_Background, *pClsid))
  223. {
  224. // We are going to treat the Background tab differently. We tell it to open
  225. // the advanced dialog. We do this so it can close the dialog if the user
  226. // clicks to open the Gallery and we need the CPL to close.
  227. hr = SHPropertyBag_WriteBOOL(pPropertyBag, SZ_PBPROP_OPENADVANCEDDLG, TRUE);
  228. }
  229. else
  230. {
  231. IAdvancedDialog * pAdvAppearDialog;
  232. hr = pBasePage->GetAdvancedDialog(&pAdvAppearDialog);
  233. if (SUCCEEDED(hr))
  234. {
  235. BOOL fEnableApply = FALSE;
  236. hr = pAdvAppearDialog->DisplayAdvancedDialog(hDlg, pPropertyBag, &fEnableApply);
  237. if (SUCCEEDED(hr) && fEnableApply)
  238. {
  239. EnableApplyButton(hDlg);
  240. g_pThemeUI->UpdatePreview(0); // The Preview settings may have changed.
  241. }
  242. pAdvAppearDialog->Release();
  243. }
  244. }
  245. pPropertyBag->Release();
  246. }
  247. pBasePage->Release();
  248. }
  249. punk->Release();
  250. }
  251. pEnumUnknown->Release();
  252. }
  253. return hr;
  254. }
  255. HRESULT SetAdvStartPage(LPTSTR pszStartPage, DWORD cchSize)
  256. {
  257. HRESULT hr = S_OK;
  258. // Does the caller want us to open the advanced dialog to a certain tab?
  259. if (g_pThemeUI)
  260. {
  261. // Yes, so open the dialog.
  262. if (!StrCmpI(pszStartPage, TEXT("Theme Settings")))
  263. {
  264. OpenAdvancedDialog(g_hDlg, &PPID_Theme);
  265. }
  266. else if (!StrCmpI(pszStartPage, TEXT("Appearance")))
  267. {
  268. OpenAdvancedDialog(g_hDlg, &PPID_BaseAppearance);
  269. }
  270. else if (!StrCmpI(pszStartPage, TEXT("Web")))
  271. {
  272. OpenAdvancedDialog(g_hDlg, &PPID_Background);
  273. StringCchCopy(pszStartPage, cchSize, L"Desktop");
  274. }
  275. }
  276. return hr;
  277. }
  278. typedef struct
  279. {
  280. LPCTSTR pszCanonical;
  281. UINT nResourceID;
  282. } CANONICAL_TO_LOCALIZE_TABMAPPING;
  283. CANONICAL_TO_LOCALIZE_TABMAPPING s_TabMapping[] =
  284. {
  285. {SZ_DISPLAYCPL_OPENTO_THEMES, IDS_TAB_THEMES},
  286. {SZ_DISPLAYCPL_OPENTO_DESKTOP, IDS_TAB_DESKTOP},
  287. {TEXT("Background"), IDS_TAB_DESKTOP}, // These are other names people may use
  288. {TEXT("Screen Saver"), IDS_TAB_SCREENSAVER}, // These are other names people may use
  289. {SZ_DISPLAYCPL_OPENTO_SCREENSAVER, IDS_TAB_SCREENSAVER},
  290. {SZ_DISPLAYCPL_OPENTO_APPEARANCE, IDS_TAB_APPEARANCE},
  291. {SZ_DISPLAYCPL_OPENTO_SETTINGS, IDS_TAB_SETTINGS},
  292. };
  293. HRESULT _TabCanonicalToLocalized(IN OUT LPTSTR pszStartPage, DWORD cchSize)
  294. {
  295. HRESULT hr = S_OK;
  296. // pszStartPage is an in AND out param
  297. for (int nIndex = 0; nIndex < ARRAYSIZE(s_TabMapping); nIndex++)
  298. {
  299. if (!StrCmpI(s_TabMapping[nIndex].pszCanonical, pszStartPage))
  300. {
  301. if (0 == s_TabMapping[nIndex].nResourceID)
  302. {
  303. hr = E_FAIL;
  304. }
  305. else
  306. {
  307. LoadString(hInstance, s_TabMapping[nIndex].nResourceID, pszStartPage, cchSize);
  308. }
  309. break;
  310. }
  311. }
  312. return hr;
  313. }
  314. ///////////////////////////////////////////////////////////////////////////////
  315. // SetStartPage checks the command line for start page by name.
  316. ///////////////////////////////////////////////////////////////////////////////
  317. #define SZ_ACTIONFLAG_THEME TEXT("/Action:OpenTheme")
  318. #define SZ_ACTIONFLAG_MSTHEME TEXT("/Action:OpenMSTheme")
  319. #define SZ_FILEFLAG TEXT("/File:\"")
  320. void SetStartPage(PROPSHEETHEADER *ppsh, LPCTSTR pszCmdLine, DWORD * pdwAction, LPTSTR pszPath, DWORD cchPathSize, LPTSTR pszStartPage, DWORD cchSize)
  321. {
  322. pszPath[0] = L'\0';
  323. pszStartPage[0] = L'\0';
  324. if (pszCmdLine)
  325. {
  326. // Strip spaces
  327. while (*pszCmdLine == TEXT(' '))
  328. {
  329. pszCmdLine++;
  330. }
  331. // Check for @ sign.
  332. if (*pszCmdLine == TEXT('@'))
  333. {
  334. LPCTSTR pszBegin;
  335. BOOL fInQuote = FALSE;
  336. int cchLen;
  337. pszCmdLine++;
  338. // Skip past a quote
  339. if (*pszCmdLine == TEXT('"'))
  340. {
  341. pszCmdLine++;
  342. fInQuote = TRUE;
  343. }
  344. // Save the beginning of the name.
  345. pszBegin = pszCmdLine;
  346. // Find the end of the name.
  347. while (pszCmdLine[0] &&
  348. (fInQuote || (pszCmdLine[0] != TEXT(' '))) &&
  349. (!fInQuote || (pszCmdLine[0] != TEXT('"'))))
  350. {
  351. pszCmdLine++;
  352. }
  353. cchLen = (int)(pszCmdLine - pszBegin);
  354. TCHAR szStartPage[MAX_PATH];
  355. StringCchCopy(szStartPage, cchLen+1, pszBegin);
  356. SetAdvStartPage(szStartPage, ARRAYSIZE(szStartPage));
  357. // Store the name in the pStartPage field.
  358. StringCchCopy(pszStartPage, cchSize, szStartPage);
  359. if (StrStrIW(pszCmdLine, SZ_ACTIONFLAG_THEME) || StrStrW(pszCmdLine, SZ_ACTIONFLAG_MSTHEME))
  360. {
  361. *pdwAction = (StrStrW(pszCmdLine, SZ_ACTIONFLAG_THEME) ? DESKACTION_OPENTHEME : DESKACTION_OPENMSTHEM);
  362. pszCmdLine = StrStrIW(pszCmdLine, SZ_FILEFLAG);
  363. if (pszCmdLine)
  364. {
  365. pszCmdLine += (ARRAYSIZE(SZ_FILEFLAG) - 1); // Skip past flag
  366. LPCWSTR pszEnd = StrStrIW(pszCmdLine, L"\"");
  367. if (pszEnd)
  368. {
  369. DWORD cchSize = (DWORD)((pszEnd - pszCmdLine) + 1);
  370. StringCchCopy(pszPath, min(cchPathSize, cchSize), pszCmdLine);
  371. }
  372. }
  373. }
  374. if (SUCCEEDED(_TabCanonicalToLocalized(pszStartPage, cchSize))) // The caller passes a canonical name but the propsheet wants to localized name
  375. {
  376. ppsh->dwFlags |= PSH_USEPSTARTPAGE;
  377. ppsh->pStartPage = pszStartPage;
  378. }
  379. }
  380. }
  381. }
  382. ///////////////////////////////////////////////////////////////////////////////
  383. // _AddDisplayPropSheetPage adds pages for outside callers...
  384. ///////////////////////////////////////////////////////////////////////////////
  385. BOOL CALLBACK _AddDisplayPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
  386. {
  387. PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *) lParam;
  388. if (ppsh)
  389. {
  390. if (hpage && (ppsh->nPages < MAX_PAGES))
  391. {
  392. ppsh->phpage[ppsh->nPages++] = hpage;
  393. return TRUE;
  394. }
  395. }
  396. return FALSE;
  397. }
  398. static int
  399. GetClInt( const TCHAR *p )
  400. {
  401. BOOL neg = FALSE;
  402. int v = 0;
  403. while( *p == TEXT(' ') )
  404. p++; // skip spaces
  405. if( *p == TEXT('-') ) // is it negative?
  406. {
  407. neg = TRUE; // yes, remember that
  408. p++; // skip '-' char
  409. }
  410. // parse the absolute portion
  411. while( ( *p >= TEXT('0') ) && ( *p <= TEXT('9') ) ) // digits only
  412. v = v * 10 + *p++ - TEXT('0'); // accumulate the value
  413. return ( neg? -v : v ); // return the result
  414. }
  415. BOOL CheckRestrictionPage(const PAGEINFO * pPageInfo)
  416. {
  417. BOOL fRestricted = SHRestricted(pPageInfo->dwPolicy1);
  418. if (!fRestricted && pPageInfo->dwPolicy2)
  419. {
  420. fRestricted = SHRestricted(pPageInfo->dwPolicy2);
  421. }
  422. return fRestricted;
  423. }
  424. ///////////////////////////////////////////////////////////////////////////////
  425. // CreateReplaceableHPSXA creates a new hpsxa that contains only the
  426. // interfaces with valid ReplacePage methods.
  427. // APPCOMPAT - EzDesk only implemented AddPages. ReplacePage is NULL for them.
  428. ///////////////////////////////////////////////////////////////////////////////
  429. typedef struct {
  430. UINT count, alloc;
  431. IShellPropSheetExt *interfaces[0];
  432. } PSXA;
  433. HPSXA
  434. CreateReplaceableHPSXA(HPSXA hpsxa)
  435. {
  436. PSXA *psxa = (PSXA *)hpsxa;
  437. DWORD cb = SIZEOF(PSXA) + SIZEOF(IShellPropSheetExt *) * psxa->alloc;
  438. PSXA *psxaRet = (PSXA *)LocalAlloc(LPTR, cb);
  439. if (psxaRet)
  440. {
  441. UINT i;
  442. psxaRet->count = 0;
  443. psxaRet->alloc = psxa->alloc;
  444. for (i=0; i<psxa->count; i++)
  445. {
  446. if (psxa->interfaces[i])
  447. {
  448. psxaRet->interfaces[psxaRet->count++] = psxa->interfaces[i];
  449. }
  450. }
  451. }
  452. return (HPSXA)psxaRet;
  453. }
  454. HRESULT AddPropSheetExtArrayToThemePageUI(IThemeUIPages * pThemeUI, HPSXA hpsxa)
  455. {
  456. HRESULT hr = E_INVALIDARG;
  457. if (pThemeUI && hpsxa)
  458. {
  459. PSXA *psxa = (PSXA *)hpsxa;
  460. IShellPropSheetExt **spsx = psxa->interfaces;
  461. UINT nIndex;
  462. for (nIndex = 0; nIndex < psxa->count; nIndex++)
  463. {
  464. if (psxa->interfaces[nIndex])
  465. {
  466. IBasePropPage * pBasePropPage;
  467. if (SUCCEEDED(psxa->interfaces[nIndex]->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePropPage))))
  468. {
  469. pThemeUI->AddBasePage(pBasePropPage);
  470. pBasePropPage->Release();
  471. }
  472. }
  473. }
  474. }
  475. return hr;
  476. }
  477. /*****************************************************************************\
  478. DESCRIPTION:
  479. If the caller gave the page index, we need to open to that page. The
  480. order of the pages has changed from Win2k to Whistler, so map the indexes.
  481. Win2K:
  482. Index 0: Background
  483. Index 1: Screen Saver
  484. Index 2: Appearance
  485. None: Web
  486. None: Effects
  487. Index 3: Settings (Index 3)
  488. Whistler: (Base Dlg)
  489. None: Themes
  490. Index 0: Background
  491. Index 1: Screen Saver
  492. Index 2: Appearance
  493. Index 3: Settings
  494. Whistler: (Adv Dlg)
  495. None: Themes Settings
  496. None: Adv Appearance
  497. None: Web
  498. None: Effects
  499. \*****************************************************************************/
  500. int UpgradeStartPageMappping(LPTSTR pszCmdLine, DWORD cchSize)
  501. {
  502. int nNewStartPage = GetClInt(pszCmdLine);
  503. if (pszCmdLine)
  504. {
  505. switch (nNewStartPage)
  506. {
  507. case 0: // Background
  508. StringCchCopy(pszCmdLine, cchSize, TEXT("@Desktop"));
  509. break;
  510. case 1: // Screen Saver
  511. case 2: // Screen Saver
  512. StringCchCopy(pszCmdLine, cchSize, TEXT("@ScreenSaver"));
  513. break;
  514. case 3: // Settings
  515. StringCchCopy(pszCmdLine, cchSize, TEXT("@Settings"));
  516. break;
  517. default:
  518. return nNewStartPage;
  519. break;
  520. }
  521. }
  522. else
  523. {
  524. return nNewStartPage;
  525. }
  526. return 0;
  527. }
  528. #define DestroyReplaceableHPSXA(hpsxa) LocalFree((HLOCAL)hpsxa)
  529. /*****************************************************************************\
  530. *
  531. * DeskShowPropSheet( HWND hwndParent )
  532. *
  533. \*****************************************************************************/
  534. void DeskShowPropSheet(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  535. {
  536. CDisplayControlPanel displayCPL;
  537. displayCPL.DisplayDialog(hInst, hwndParent, pszCmdline);
  538. }
  539. //===========================
  540. // *** IUnknown Interface ***
  541. //===========================
  542. ULONG CDisplayControlPanel::AddRef()
  543. {
  544. return InterlockedIncrement(&m_cRef);
  545. }
  546. ULONG CDisplayControlPanel::Release()
  547. {
  548. ASSERT( 0 != m_cRef );
  549. ULONG cRef = InterlockedDecrement(&m_cRef);
  550. if ( 0 == cRef )
  551. {
  552. delete this;
  553. }
  554. else if ((1 == cRef) && m_hBackgroundThreads)
  555. {
  556. SetEvent(m_hBackgroundThreads);
  557. }
  558. return cRef;
  559. }
  560. HRESULT CDisplayControlPanel::QueryInterface(REFIID riid, void **ppvObj)
  561. {
  562. HRESULT hr = E_NOINTERFACE;
  563. static const QITAB qit[] = {
  564. QITABENT(CDisplayControlPanel, IObjectWithSite),
  565. { 0 },
  566. };
  567. return QISearch(this, qit, riid, ppvObj);
  568. }
  569. CDisplayControlPanel::CDisplayControlPanel(void) : m_cRef(1)
  570. {
  571. m_hBackgroundThreads = NULL;
  572. }
  573. CDisplayControlPanel::~CDisplayControlPanel(void)
  574. {
  575. if (m_hBackgroundThreads)
  576. {
  577. CloseHandle(m_hBackgroundThreads);
  578. m_hBackgroundThreads = NULL;
  579. }
  580. }
  581. // Wait 30 seconds for hung apps to process our message before we give up.
  582. // It would be nice to wait longer, but if the user tries to launch the Display
  583. // Control Panel again, it will not launch because we are still running. The only
  584. // thing that we will give up on doing after 30 seconds it notifying apps. In the worse
  585. // case the user will need to log-off and back in to get apps to refresh.
  586. #define MAX_WAITFORHUNGAPPS (30)
  587. void CDisplayControlPanel::DisplayDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  588. {
  589. if (SUCCEEDED(CoInitialize(NULL)))
  590. {
  591. SHSetInstanceExplorer(SAFECAST(this, IUnknown *));
  592. _ShowDialog(hInst, hwndParent, pszCmdline);
  593. // Wait until the background threads finish.
  594. if (m_cRef > 1)
  595. {
  596. m_hBackgroundThreads = CreateEvent(NULL, FALSE, FALSE, NULL);
  597. if (m_hBackgroundThreads && (m_cRef > 1))
  598. {
  599. DWORD dwResult = SHProcessMessagesUntilEvent(NULL, m_hBackgroundThreads, (MAX_WAITFORHUNGAPPS * 1000));
  600. if (WAIT_TIMEOUT == dwResult)
  601. {
  602. TraceMsg(TF_GENERAL, "A thread hung and we needed to shutdown while it was still running.");
  603. }
  604. Sleep(100);
  605. }
  606. }
  607. SHSetInstanceExplorer(NULL);
  608. CoUninitialize();
  609. }
  610. }
  611. void CDisplayControlPanel::_ShowDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  612. {
  613. HPROPSHEETPAGE hpsp, ahPages[MAX_PAGES];
  614. HPSXA hpsxa = NULL;
  615. PROPSHEETPAGE psp;
  616. PROPSHEETHEADER psh;
  617. int i;
  618. DWORD exitparam = 0UL;
  619. HRESULT hr = S_OK;
  620. TCHAR szCmdLine[MAX_PATH];
  621. StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), (pszCmdline ? pszCmdline : TEXT("")));
  622. // check if whole sheet is locked out
  623. if (SHRestricted(REST_NODISPLAYCPL))
  624. {
  625. TCHAR szMessage[255],szTitle[255];
  626. LoadString( hInst, IDS_DISPLAY_DISABLED, szMessage, ARRAYSIZE(szMessage) );
  627. LoadString( hInst, IDS_DISPLAY_TITLE, szTitle, ARRAYSIZE(szTitle) );
  628. MessageBox( hwndParent, szMessage, szTitle, MB_OK | MB_ICONINFORMATION );
  629. return;
  630. }
  631. // Create the property sheet
  632. ZeroMemory(&psh, sizeof(psh));
  633. psh.dwSize = sizeof(PROPSHEETHEADER);
  634. psh.dwFlags = (PSH_PROPTITLE | PSH_USECALLBACK);
  635. psh.hwndParent = hwndParent;
  636. psh.hInstance = hInst;
  637. psh.pszCaption = MAKEINTRESOURCE(IDS_DISPLAY_TITLE);
  638. psh.nPages = 0;
  639. psh.phpage = ahPages;
  640. psh.nStartPage = 0;
  641. psh.pfnCallback = NULL;
  642. if (szCmdLine && szCmdLine[0] && (TEXT('@') != szCmdLine[0]))
  643. {
  644. psh.nStartPage = UpgradeStartPageMappping(szCmdLine, ARRAYSIZE(szCmdLine)); // We changed the order so do the mapping
  645. }
  646. ZeroMemory( &psp, sizeof(psp) );
  647. psp.dwSize = sizeof(psp);
  648. psp.dwFlags = PSP_DEFAULT;
  649. psp.hInstance = hInst;
  650. // Build the property sheet. If we are under setup, then just include
  651. // the "settings" page, and no otheres
  652. if (!g_pThemeUI)
  653. {
  654. // CoCreate Themes, Appearance, and Advanced Appearance tabs
  655. hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &g_pThemeUI));
  656. }
  657. if (SUCCEEDED(hr))
  658. {
  659. DWORD dwExecMode;
  660. if (g_pThemeUI && (SUCCEEDED(g_pThemeUI->GetExecMode(&dwExecMode))) && (dwExecMode == EM_NORMAL))
  661. {
  662. if (!GetSystemMetrics(SM_CLEANBOOT))
  663. {
  664. hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE,
  665. REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), 8);
  666. }
  667. for (i = 0; i < C_PAGES_DESK; i++)
  668. {
  669. BOOL fHideThisPage = FALSE;
  670. if (CheckRestrictionPage(&aPageInfo[i]))
  671. {
  672. // This page is locked out by admin, don't put it up
  673. fHideThisPage = TRUE;
  674. }
  675. if (-1 == aPageInfo[i].nExtensionID)
  676. {
  677. psp.pszTemplate = MAKEINTRESOURCE(aPageInfo[i].id);
  678. psp.pfnDlgProc = aPageInfo[i].pfnDlgProc;
  679. psp.dwFlags = PSP_DEFAULT;
  680. psp.lParam = 0L;
  681. if (!fHideThisPage && (psp.pfnDlgProc == BackgroundDlgProc))
  682. {
  683. // This page can be overridden by extensions
  684. if( hpsxa )
  685. {
  686. UINT cutoff = psh.nPages;
  687. UINT added = 0;
  688. HPSXA hpsxaReplace = CreateReplaceableHPSXA(hpsxa);
  689. if (hpsxaReplace)
  690. {
  691. added = SHReplaceFromPropSheetExtArray( hpsxaReplace, CPLPAGE_DISPLAY_BACKGROUND,
  692. _AddDisplayPropSheetPage, (LPARAM)&psh);
  693. DestroyReplaceableHPSXA(hpsxaReplace);
  694. }
  695. if (added)
  696. {
  697. if (psh.nStartPage >= cutoff)
  698. psh.nStartPage += added-1;
  699. continue;
  700. }
  701. }
  702. }
  703. if (!fHideThisPage && (hpsp = CreatePropertySheetPage(&psp)))
  704. {
  705. psh.phpage[psh.nPages++] = hpsp;
  706. }
  707. }
  708. else if (g_pThemeUI && !fHideThisPage)
  709. {
  710. IBasePropPage * pBasePage = NULL;
  711. // add extensions from the registry
  712. // CAUTION: Do not check for "fHideThisPage" here. We need to add the pages for
  713. // property sheet extensions even if the "Settings" page is hidden.
  714. if (i == IPI_SETTINGS && hpsxa)
  715. {
  716. UINT cutoff = psh.nPages;
  717. UINT added = SHAddFromPropSheetExtArray(hpsxa, _AddDisplayPropSheetPage, (LPARAM)&psh);
  718. if (psh.nStartPage >= cutoff)
  719. psh.nStartPage += added;
  720. }
  721. switch (aPageInfo[i].id)
  722. {
  723. case 0:
  724. hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[i].nExtensionID);
  725. break;
  726. case DLG_SCREENSAVER:
  727. hr = CoCreateInstance(CLSID_ScreenSaverPage, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage));
  728. break;
  729. case DLG_BACKGROUND:
  730. hr = CoCreateInstance(CLSID_CDeskHtmlProp, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage));
  731. break;
  732. default:
  733. AssertMsg(0, TEXT("The value must be specified"));
  734. break;
  735. };
  736. if (pBasePage)
  737. {
  738. IShellPropSheetExt * pspse = NULL;
  739. // If they implement IShellPropSheetExt, then add their base pages.
  740. if (SUCCEEDED(pBasePage->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse))))
  741. {
  742. hr = pspse->AddPages(_AddDisplayPropSheetPage, (LPARAM)&psh);
  743. pspse->Release();
  744. }
  745. hr = g_pThemeUI->AddBasePage(pBasePage);
  746. pBasePage->Release();
  747. }
  748. }
  749. }
  750. if (hpsxa)
  751. {
  752. // Have the dynamically added pages added to IThemeUIPages.
  753. AddPropSheetExtArrayToThemePageUI(g_pThemeUI, hpsxa);
  754. }
  755. // add a fake settings page to fool OEM extensions
  756. // !!! this page must be last !!!
  757. if (hpsxa)
  758. {
  759. g_pThemeUI->AddFakeSettingsPage((LPVOID)&psh);
  760. }
  761. }
  762. else
  763. {
  764. // For the SETUP case, only the display page should show up.
  765. hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[IPI_SETTINGS].nExtensionID);
  766. }
  767. if (psh.nStartPage >= psh.nPages)
  768. psh.nStartPage = 0;
  769. if (psh.nPages)
  770. {
  771. DWORD dwAction = DESKACTION_NONE;
  772. TCHAR szStartPage[MAX_PATH];
  773. WCHAR szOpenPath[MAX_PATH];
  774. IPropertyBag * pPropertyBag;
  775. SetStartPage(&psh, szCmdLine, &dwAction, szOpenPath, ARRAYSIZE(szOpenPath), szStartPage, ARRAYSIZE(szStartPage));
  776. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  777. if (SUCCEEDED(hr))
  778. {
  779. VARIANT var;
  780. if (DESKACTION_NONE != dwAction)
  781. {
  782. var.vt = VT_LPWSTR;
  783. var.bstrVal = szOpenPath;
  784. hr = pPropertyBag->Write(((DESKACTION_OPENTHEME == dwAction) ? SZ_PBPROP_THEME_LAUNCHTHEME : SZ_PBPROP_APPEARANCE_LAUNCHMSTHEME), &var);
  785. }
  786. // The following SZ_PBPROP_PREOPEN call will save a "Custom.theme" so users can always go back to
  787. // their settings if they don't like changes they make in the CPL.
  788. pPropertyBag->Write(SZ_PBPROP_PREOPEN, NULL);
  789. pPropertyBag->Release();
  790. }
  791. if (PropertySheet(&psh) == ID_PSRESTARTWINDOWS)
  792. {
  793. exitparam = EWX_REBOOT;
  794. }
  795. }
  796. if (g_pThemeUI)
  797. {
  798. IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
  799. g_pThemeUI->Release();
  800. g_pThemeUI = NULL;
  801. }
  802. // free any loaded extensions
  803. if (hpsxa)
  804. {
  805. SHDestroyPropSheetExtArray(hpsxa);
  806. }
  807. if (exitparam == EWX_REBOOT)
  808. {
  809. RestartDialogEx(hwndParent, NULL, exitparam, (SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_RECONFIG));
  810. }
  811. }
  812. return;
  813. }
  814. DWORD gdwCoverStyle = WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
  815. HWND FAR PASCAL CreateCoverWindow( DWORD flags )
  816. {
  817. HWND hwndCover = CreateWindowEx( gdwCoverStyle,
  818. sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | flags,
  819. GetSystemMetrics( SM_XVIRTUALSCREEN ),
  820. GetSystemMetrics( SM_YVIRTUALSCREEN ),
  821. GetSystemMetrics( SM_CXVIRTUALSCREEN ),
  822. GetSystemMetrics( SM_CYVIRTUALSCREEN ),
  823. NULL, NULL, hInstance, NULL );
  824. if( hwndCover )
  825. {
  826. SetForegroundWindow( hwndCover );
  827. if (flags & COVER_NOPAINT)
  828. SetCursor(LoadCursor(NULL, IDC_WAIT));
  829. UpdateWindow( hwndCover);
  830. }
  831. return hwndCover;
  832. }
  833. ///////////////////////////////////////////////////////////////////////////////
  834. // CoverWndProc (see CreateCoverWindow)
  835. ///////////////////////////////////////////////////////////////////////////////
  836. #define WM_PRIV_KILL_LATER (WM_APP + 100) //Private message to kill ourselves later.
  837. LRESULT CALLBACK
  838. CoverWindowProc( HWND window, UINT message, WPARAM wparam, LPARAM lparam )
  839. {
  840. switch( message )
  841. {
  842. case WM_CREATE:
  843. SetTimer( window, ID_CVRWND_TIMER, CMSEC_COVER_WINDOW_TIMEOUT, NULL );
  844. break;
  845. case WM_TIMER:
  846. // Times up... Shut ourself down
  847. if (wparam == ID_CVRWND_TIMER)
  848. DestroyWindow(window);
  849. break;
  850. case WM_ERASEBKGND:
  851. // NOTE: assumes our class brush is the NULL_BRUSH stock object
  852. if( !( GetWindowLong( window, GWL_STYLE ) & COVER_NOPAINT ) )
  853. {
  854. HDC dc = (HDC)wparam;
  855. RECT rc;
  856. if( GetClipBox( dc, (LPRECT)&rc ) != NULLREGION )
  857. {
  858. FillRect( dc, (LPRECT)&rc, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
  859. // HACK: make sure fillrect is done before we return
  860. // this is to better hide flicker during dynares-crap
  861. GetPixel( dc, rc.left + 1, rc.top + 1 );
  862. }
  863. }
  864. break;
  865. // We post a private message to ourselves because:
  866. // When WM_CLOSE is processed by this window, it calls DestroyWindow() which results in
  867. // WM_ACTIVATE (WA_INACTIVE) message to be sent to this window. If this code calls
  868. // DestroyWindow again, it causes a loop. So, instead of calling DestroyWindow immediately,
  869. // we post ourselves a message and destroy us letter.
  870. case WM_ACTIVATE:
  871. if( GET_WM_ACTIVATE_STATE( wparam, lparam ) == WA_INACTIVE )
  872. {
  873. PostMessage( window, WM_PRIV_KILL_LATER, 0L, 0L );
  874. return 1L;
  875. }
  876. break;
  877. case WM_PRIV_KILL_LATER:
  878. DestroyWindow(window);
  879. break;
  880. case WM_DESTROY:
  881. KillTimer(window, ID_CVRWND_TIMER);
  882. break;
  883. }
  884. return DefWindowProc( window, message, wparam, lparam );
  885. }
  886. BOOL _FindCoverWindowCallback(HWND hwnd, LPARAM lParam)
  887. {
  888. TCHAR szClass[MAX_PATH];
  889. HWND *phwnd = (HWND*)lParam;
  890. if( !GetClassName(hwnd, szClass, ARRAYSIZE(szClass)) )
  891. return TRUE;
  892. if( StrCmp(szClass, sc_szCoverClass) == 0 )
  893. {
  894. if( phwnd )
  895. *phwnd = hwnd;
  896. return FALSE;
  897. }
  898. return TRUE;
  899. }
  900. LONG APIENTRY CPlApplet(
  901. HWND hwnd,
  902. WORD message,
  903. LPARAM wParam,
  904. LPARAM lParam)
  905. {
  906. LPCPLINFO lpCPlInfo;
  907. LPNEWCPLINFO lpNCPlInfo;
  908. HWND hwndCover;
  909. switch (message)
  910. {
  911. case CPL_INIT: // Is any one there ?
  912. // Init the common controls
  913. if (!DeskInitCpl())
  914. return 0;
  915. // Load ONE string for emergencies.
  916. LoadString (hInstance, IDS_DISPLAY_TITLE, gszDeskCaption, ARRAYSIZE(gszDeskCaption));
  917. return !0;
  918. case CPL_GETCOUNT: // How many applets do you support ?
  919. return 1;
  920. case CPL_INQUIRE: // Fill CplInfo structure
  921. lpCPlInfo = (LPCPLINFO)lParam;
  922. lpCPlInfo->idIcon = IDI_DISPLAY;
  923. lpCPlInfo->idName = IDS_NAME;
  924. lpCPlInfo->idInfo = IDS_INFO;
  925. lpCPlInfo->lData = 0;
  926. break;
  927. case CPL_NEWINQUIRE:
  928. lpNCPlInfo = (LPNEWCPLINFO)lParam;
  929. lpNCPlInfo->hIcon = LoadIcon(hInstance, (LPTSTR) MAKEINTRESOURCE(IDI_DISPLAY));
  930. LoadString(hInstance, IDS_NAME, lpNCPlInfo->szName, ARRAYSIZE(lpNCPlInfo->szName));
  931. if (!LoadString(hInstance, IDS_INFO, lpNCPlInfo->szInfo, ARRAYSIZE(lpNCPlInfo->szInfo)))
  932. lpNCPlInfo->szInfo[0] = (TCHAR) 0;
  933. lpNCPlInfo->dwSize = sizeof( NEWCPLINFO );
  934. lpNCPlInfo->lData = 0;
  935. lpNCPlInfo->dwHelpContext = 0;
  936. lpNCPlInfo->szHelpFile[0] = 0;
  937. return TRUE;
  938. case CPL_DBLCLK: // You have been chosen to run
  939. /*
  940. * One of your applets has been double-clicked.
  941. * wParam is an index from 0 to (NUM_APPLETS-1)
  942. * lParam is the lData value associated with the applet
  943. */
  944. lParam = 0L;
  945. // fall through...
  946. case CPL_STARTWPARMS:
  947. DeskShowPropSheet( hInstance, hwnd, (LPTSTR)lParam );
  948. // ensure that any cover windows we've created have been destroyed
  949. do
  950. {
  951. hwndCover = 0;
  952. EnumWindows( _FindCoverWindowCallback, (LPARAM)&hwndCover );
  953. if( hwndCover )
  954. {
  955. DestroyWindow( hwndCover );
  956. }
  957. }
  958. while( hwndCover );
  959. return TRUE; // Tell RunDLL.exe that I succeeded
  960. case CPL_EXIT: // You must really die
  961. if (g_hdcMem)
  962. {
  963. ReleaseDC(NULL, g_hdcMem);
  964. g_hdcMem = NULL;
  965. }
  966. // Fall thru...
  967. case CPL_STOP: // You must die
  968. if (g_pThemeUI)
  969. {
  970. IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
  971. g_pThemeUI->Release();
  972. g_pThemeUI = NULL;
  973. }
  974. break;
  975. case CPL_SELECT: // You have been selected
  976. /*
  977. * Sent once for each applet prior to the CPL_EXIT msg.
  978. * wParam is an index from 0 to (NUM_APPLETS-1)
  979. * lParam is the lData value associated with the applet
  980. */
  981. break;
  982. //
  983. // Private message sent when this applet is running under "Setup"
  984. //
  985. case CPL_SETUP:
  986. if (g_pThemeUI)
  987. {
  988. g_pThemeUI->SetExecMode(EM_SETUP);
  989. }
  990. break;
  991. // Private message used by userenv.dll to refresh the display colors
  992. case CPL_POLICYREFRESH:
  993. if (g_pThemeUI) // If this object doesn't exist, then we don't need to refresh anything.
  994. {
  995. IPreviewSystemMetrics * ppsm;
  996. if (SUCCEEDED(g_pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm))))
  997. {
  998. ppsm->RefreshColors();
  999. ppsm->Release();
  1000. }
  1001. }
  1002. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, FALSE);
  1003. break;
  1004. }
  1005. return 0L;
  1006. }
  1007. BOOL WINAPI DeskSetCurrentSchemeW(IN LPCWSTR pwzSchemeName)
  1008. {
  1009. BOOL fSuccess = FALSE;
  1010. IThemeUIPages * pThemeUI = NULL;
  1011. HRESULT hr;
  1012. HRESULT hrOle = SHCoInitialize();
  1013. if (g_pThemeUI)
  1014. {
  1015. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1016. }
  1017. else
  1018. {
  1019. hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1020. }
  1021. if (SUCCEEDED(hr))
  1022. {
  1023. IPreviewSystemMetrics * ppsm;
  1024. hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm));
  1025. if (SUCCEEDED(hr))
  1026. {
  1027. hr = ppsm->DeskSetCurrentScheme(pwzSchemeName);
  1028. ppsm->Release();
  1029. }
  1030. fSuccess = SUCCEEDED(hr);
  1031. pThemeUI->Release();
  1032. }
  1033. SHCoUninitialize(hrOle);
  1034. return fSuccess;
  1035. }
  1036. //------------------------------------------------------------------------------------------------
  1037. // This function gets the current DPI, reads the last updated DPI from registry and compares
  1038. // these two. If these two are equal, it returns immediately.
  1039. // If these two DPI values are different, then it updates the size of UI fonts to reflect the
  1040. // change in the DPI values.
  1041. //
  1042. // This function is called from explorer sothat when DPI value is changed by admin and then every
  1043. // other user who logs-in gets this change.
  1044. //------------------------------------------------------------------------------------------------
  1045. void WINAPI UpdateUIfontsDueToDPIchange(int iOldDPI, int iNewDPI)
  1046. {
  1047. BOOL fSuccess = FALSE;
  1048. IThemeManager * pThemeMgr = NULL;
  1049. HRESULT hr;
  1050. HRESULT hrOle = SHCoInitialize();
  1051. if (g_pThemeUI)
  1052. {
  1053. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeManager, &pThemeMgr));
  1054. }
  1055. else
  1056. {
  1057. hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeManager, &pThemeMgr));
  1058. }
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. IPropertyBag * pPropertyBag;
  1062. hr = GetPageByCLSID(pThemeMgr, &PPID_BaseAppearance, &pPropertyBag);
  1063. if (SUCCEEDED(hr))
  1064. {
  1065. hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_DPI_APPLIED_VALUE, iOldDPI); // We are going to pretend we had the old DPI to force the scale to happen.
  1066. hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_DPI_MODIFIED_VALUE, iNewDPI);
  1067. if (SUCCEEDED(hr))
  1068. {
  1069. hr = pThemeMgr->ApplyNow();
  1070. }
  1071. pPropertyBag->Release();
  1072. }
  1073. fSuccess = SUCCEEDED(hr);
  1074. pThemeMgr->Release();
  1075. }
  1076. SHCoUninitialize(hrOle);
  1077. }
  1078. BOOL DeskSetCurrentSchemeA(IN LPCSTR pszSchemeName)
  1079. {
  1080. WCHAR wzSchemeName[MAX_PATH];
  1081. MultiByteToWideChar(CP_ACP, 0, pszSchemeName, -1, wzSchemeName, ARRAYSIZE(wzSchemeName));
  1082. return DeskSetCurrentSchemeW(wzSchemeName);
  1083. }
  1084. STDAPI UpdateCharsetChanges(void)
  1085. {
  1086. BOOL fSuccess = FALSE;
  1087. IThemeUIPages * pThemeUI = NULL;
  1088. HRESULT hr;
  1089. HRESULT hrOle = SHCoInitialize();
  1090. if (g_pThemeUI)
  1091. {
  1092. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1093. }
  1094. else
  1095. {
  1096. hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1097. }
  1098. if (SUCCEEDED(hr))
  1099. {
  1100. IPreviewSystemMetrics * ppsm;
  1101. hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm));
  1102. if (SUCCEEDED(hr))
  1103. {
  1104. hr = ppsm->UpdateCharsetChanges();
  1105. ppsm->Release();
  1106. }
  1107. pThemeUI->Release();
  1108. }
  1109. SHCoUninitialize(hrOle);
  1110. return hr;
  1111. }