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.

1730 lines
50 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 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. BOOL AreExtraMonitorsDisabledOnPersonal(void)
  134. {
  135. BOOL fIsDisabled = IsOS(OS_PERSONAL);
  136. if (fIsDisabled)
  137. {
  138. // TODO: Insert call to SystemParametersInfo() to see if there are video cards that we had to disable.
  139. fIsDisabled = FALSE;
  140. }
  141. return fIsDisabled;
  142. }
  143. /*---------------------------------------------------------
  144. **
  145. **---------------------------------------------------------*/
  146. HBITMAP FAR LoadMonitorBitmap( BOOL bFillDesktop )
  147. {
  148. HBITMAP hbm = NULL;
  149. if (g_pThemeUI)
  150. {
  151. g_pThemeUI->LoadMonitorBitmap(bFillDesktop, &hbm);
  152. }
  153. return hbm;
  154. }
  155. int DisplaySaveSettings(PVOID pContext, HWND hwnd)
  156. {
  157. int iRet = 0;
  158. if (g_pThemeUI)
  159. {
  160. g_pThemeUI->DisplaySaveSettings(pContext, hwnd, &iRet);
  161. }
  162. return iRet;
  163. }
  164. ///////////////////////////////////////////////////////////////////////////////
  165. //
  166. // Messagebox wrapper
  167. //
  168. //
  169. ///////////////////////////////////////////////////////////////////////////////
  170. int
  171. FmtMessageBox(
  172. HWND hwnd,
  173. UINT fuStyle,
  174. DWORD dwTitleID,
  175. DWORD dwTextID)
  176. {
  177. TCHAR Title[256];
  178. TCHAR Text[2000];
  179. LoadString(hInstance, dwTextID, Text, ARRAYSIZE(Text));
  180. LoadString(hInstance, dwTitleID, Title, ARRAYSIZE(Title));
  181. return (ShellMessageBox(hInstance, hwnd, Text, Title, fuStyle));
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////
  184. //
  185. // InstallScreenSaver
  186. //
  187. // Provides a RUNDLL32-callable routine to install a screen saver
  188. //
  189. ///////////////////////////////////////////////////////////////////////////////
  190. #ifdef UNICODE
  191. //
  192. // Windows NT:
  193. //
  194. // Thunk ANSI version to the Unicode function
  195. //
  196. void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw );
  197. void WINAPI InstallScreenSaverA( HWND wnd, HINSTANCE inst, LPSTR cmd, int shw )
  198. {
  199. LPWSTR pwszCmd;
  200. int cch;
  201. cch = MultiByteToWideChar( CP_ACP, 0, cmd, -1, NULL, 0);
  202. if (cch == 0)
  203. return;
  204. pwszCmd = (LPWSTR) LocalAlloc( LMEM_FIXED, cch * SIZEOF(TCHAR) );
  205. if (pwszCmd == NULL)
  206. return;
  207. if (0 != MultiByteToWideChar( CP_ACP, 0, cmd, -1, pwszCmd, cch))
  208. {
  209. InstallScreenSaverW(wnd, inst, pwszCmd, shw);
  210. }
  211. LocalFree(pwszCmd);
  212. }
  213. # define REAL_INSTALL_SCREEN_SAVER InstallScreenSaverW
  214. #else
  215. //
  216. // Windows 95:
  217. //
  218. // Stub out Unicode version
  219. //
  220. void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw )
  221. {
  222. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  223. return;
  224. }
  225. # define REAL_INSTALL_SCREEN_SAVER InstallScreenSaverA
  226. #endif
  227. void WINAPI REAL_INSTALL_SCREEN_SAVER( HWND wnd, HINSTANCE inst, LPTSTR cmd, int shw )
  228. {
  229. TCHAR buf[ MAX_PATH ];
  230. int timeout;
  231. lstrcpy( buf, cmd );
  232. PathGetShortPath( buf ); // so msscenes doesn't die
  233. WritePrivateProfileString( TEXT("boot"), TEXT("SCRNSAVE.EXE"), buf, TEXT("system.ini") );
  234. SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, TRUE, NULL,
  235. SPIF_UPDATEINIFILE );
  236. // make sure the user has a reasonable timeout set
  237. SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &timeout, 0 );
  238. if( timeout <= 0 )
  239. {
  240. // 15 minutes seems like a nice default
  241. SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, 900, NULL,
  242. SPIF_UPDATEINIFILE );
  243. }
  244. // bring up the screen saver page on our rundll
  245. #ifdef UNICODE
  246. Control_RunDLLW( wnd, inst, TEXT("DESK.CPL,,1"), shw );
  247. #else
  248. Control_RunDLL( wnd, inst, TEXT("DESK.CPL,,1"), shw );
  249. #endif
  250. }
  251. /*****************************************************************************\
  252. *
  253. * DeskInitCpl( void )
  254. *
  255. \*****************************************************************************/
  256. BOOL DeskInitCpl(void) {
  257. //
  258. // Private Debug stuff
  259. //
  260. #if ANDREVA_DBG
  261. g_dwTraceFlags = 0xFFFFFFFF;
  262. #endif
  263. InitCommonControls();
  264. CreateGlobals();
  265. return TRUE;
  266. }
  267. HRESULT OpenAdvancedDialog(HWND hDlg, const CLSID * pClsid)
  268. {
  269. HRESULT hr = E_FAIL;
  270. IEnumUnknown * pEnumUnknown;
  271. hr = g_pThemeUI->GetBasePagesEnum(&pEnumUnknown);
  272. if (SUCCEEDED(hr))
  273. {
  274. IUnknown * punk;
  275. hr = IEnumUnknown_FindCLSID(pEnumUnknown, *pClsid, &punk);
  276. if (SUCCEEDED(hr))
  277. {
  278. IBasePropPage * pBasePage;
  279. hr = punk->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePage));
  280. if (SUCCEEDED(hr))
  281. {
  282. IPropertyBag * pPropertyBag;
  283. hr = punk->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  284. if (SUCCEEDED(hr))
  285. {
  286. if (IsEqualCLSID(PPID_Background, *pClsid))
  287. {
  288. // We are going to treat the Background tab differently. We tell it to open
  289. // the advanced dialog. We do this so it can close the dialog if the user
  290. // clicks to open the Gallery and we need the CPL to close.
  291. hr = SHPropertyBag_WriteBOOL(pPropertyBag, SZ_PBPROP_OPENADVANCEDDLG, TRUE);
  292. }
  293. else
  294. {
  295. IAdvancedDialog * pAdvAppearDialog;
  296. hr = pBasePage->GetAdvancedDialog(&pAdvAppearDialog);
  297. if (SUCCEEDED(hr))
  298. {
  299. BOOL fEnableApply = FALSE;
  300. hr = pAdvAppearDialog->DisplayAdvancedDialog(hDlg, pPropertyBag, &fEnableApply);
  301. if (SUCCEEDED(hr) && fEnableApply)
  302. {
  303. EnableApplyButton(hDlg);
  304. g_pThemeUI->UpdatePreview(0); // The Preview settings may have changed.
  305. }
  306. pAdvAppearDialog->Release();
  307. }
  308. }
  309. pPropertyBag->Release();
  310. }
  311. pBasePage->Release();
  312. }
  313. punk->Release();
  314. }
  315. pEnumUnknown->Release();
  316. }
  317. return hr;
  318. }
  319. HRESULT SetAdvStartPage(LPTSTR pszStartPage, DWORD cchSize)
  320. {
  321. HRESULT hr = S_OK;
  322. // Does the caller want us to open the advanced dialog to a certain tab?
  323. if (g_pThemeUI)
  324. {
  325. // Yes, so open the dialog.
  326. if (!StrCmpI(pszStartPage, TEXT("Theme Settings")))
  327. {
  328. OpenAdvancedDialog(g_hDlg, &PPID_Theme);
  329. }
  330. else if (!StrCmpI(pszStartPage, TEXT("Appearance")))
  331. {
  332. OpenAdvancedDialog(g_hDlg, &PPID_BaseAppearance);
  333. }
  334. else if (!StrCmpI(pszStartPage, TEXT("Web")))
  335. {
  336. OpenAdvancedDialog(g_hDlg, &PPID_Background);
  337. StrCpyNW(pszStartPage, L"Desktop", cchSize);
  338. }
  339. }
  340. return hr;
  341. }
  342. typedef struct
  343. {
  344. LPCTSTR pszCanonical;
  345. UINT nResourceID;
  346. } CANONICAL_TO_LOCALIZE_TABMAPPING;
  347. CANONICAL_TO_LOCALIZE_TABMAPPING s_TabMapping[] =
  348. {
  349. {SZ_DISPLAYCPL_OPENTO_THEMES, IDS_TAB_THEMES},
  350. {SZ_DISPLAYCPL_OPENTO_DESKTOP, IDS_TAB_DESKTOP},
  351. {TEXT("Background"), IDS_TAB_DESKTOP}, // These are other names people may use
  352. {TEXT("Screen Saver"), IDS_TAB_SCREENSAVER}, // These are other names people may use
  353. {SZ_DISPLAYCPL_OPENTO_SCREENSAVER, IDS_TAB_SCREENSAVER},
  354. {SZ_DISPLAYCPL_OPENTO_APPEARANCE, IDS_TAB_APPEARANCE},
  355. {SZ_DISPLAYCPL_OPENTO_SETTINGS, IDS_TAB_SETTINGS},
  356. };
  357. HRESULT _TabCanonicalToLocalized(IN OUT LPTSTR pszStartPage, DWORD cchSize)
  358. {
  359. HRESULT hr = S_OK;
  360. // pszStartPage is an in AND out param
  361. for (int nIndex = 0; nIndex < ARRAYSIZE(s_TabMapping); nIndex++)
  362. {
  363. if (!StrCmpI(s_TabMapping[nIndex].pszCanonical, pszStartPage))
  364. {
  365. if (0 == s_TabMapping[nIndex].nResourceID)
  366. {
  367. hr = E_FAIL;
  368. }
  369. else
  370. {
  371. LoadString(hInstance, s_TabMapping[nIndex].nResourceID, pszStartPage, cchSize);
  372. }
  373. break;
  374. }
  375. }
  376. return hr;
  377. }
  378. ///////////////////////////////////////////////////////////////////////////////
  379. // SetStartPage checks the command line for start page by name.
  380. ///////////////////////////////////////////////////////////////////////////////
  381. #define SZ_ACTIONFLAG_THEME TEXT("/Action:OpenTheme")
  382. #define SZ_ACTIONFLAG_MSTHEME TEXT("/Action:OpenMSTheme")
  383. #define SZ_FILEFLAG TEXT("/File:\"")
  384. void SetStartPage(PROPSHEETHEADER *ppsh, LPCTSTR pszCmdLine, DWORD * pdwAction, LPTSTR pszPath, DWORD cchPathSize, LPTSTR pszStartPage, DWORD cchSize)
  385. {
  386. StrCpyNW(pszPath, L"", cchPathSize);
  387. StrCpyNW(pszStartPage, L"", cchSize);
  388. if (pszCmdLine)
  389. {
  390. // Strip spaces
  391. while (*pszCmdLine == TEXT(' '))
  392. {
  393. pszCmdLine++;
  394. }
  395. // Check for @ sign.
  396. if (*pszCmdLine == TEXT('@'))
  397. {
  398. LPCTSTR pszBegin;
  399. BOOL fInQuote = FALSE;
  400. int cchLen;
  401. pszCmdLine++;
  402. // Skip past a quote
  403. if (*pszCmdLine == TEXT('"'))
  404. {
  405. pszCmdLine++;
  406. fInQuote = TRUE;
  407. }
  408. // Save the beginning of the name.
  409. pszBegin = pszCmdLine;
  410. // Find the end of the name.
  411. while (pszCmdLine[0] &&
  412. (fInQuote || (pszCmdLine[0] != TEXT(' '))) &&
  413. (!fInQuote || (pszCmdLine[0] != TEXT('"'))))
  414. {
  415. pszCmdLine++;
  416. }
  417. cchLen = (int)(pszCmdLine - pszBegin);
  418. TCHAR szStartPage[MAX_PATH];
  419. StrCpyN(szStartPage, pszBegin, cchLen+1);
  420. SetAdvStartPage(szStartPage, ARRAYSIZE(szStartPage));
  421. // Store the name in the pStartPage field.
  422. StrCpyN(pszStartPage, szStartPage, cchSize);
  423. if (StrStrIW(pszCmdLine, SZ_ACTIONFLAG_THEME) || StrStrW(pszCmdLine, SZ_ACTIONFLAG_MSTHEME))
  424. {
  425. *pdwAction = (StrStrW(pszCmdLine, SZ_ACTIONFLAG_THEME) ? DESKACTION_OPENTHEME : DESKACTION_OPENMSTHEM);
  426. pszCmdLine = StrStrIW(pszCmdLine, SZ_FILEFLAG);
  427. if (pszCmdLine)
  428. {
  429. pszCmdLine += (ARRAYSIZE(SZ_FILEFLAG) - 1); // Skip past flag
  430. LPCWSTR pszEnd = StrStrIW(pszCmdLine, L"\"");
  431. if (pszEnd)
  432. {
  433. DWORD cchSize = (DWORD)((pszEnd - pszCmdLine) + 1);
  434. StrCpyNW(pszPath, pszCmdLine, min(cchPathSize, cchSize));
  435. }
  436. }
  437. }
  438. if (SUCCEEDED(_TabCanonicalToLocalized(pszStartPage, cchSize))) // The caller passes a canonical name but the propsheet wants to localized name
  439. {
  440. ppsh->dwFlags |= PSH_USEPSTARTPAGE;
  441. ppsh->pStartPage = pszStartPage;
  442. }
  443. }
  444. }
  445. }
  446. ///////////////////////////////////////////////////////////////////////////////
  447. // _AddDisplayPropSheetPage adds pages for outside callers...
  448. ///////////////////////////////////////////////////////////////////////////////
  449. BOOL CALLBACK _AddDisplayPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
  450. {
  451. PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *) lParam;
  452. if (ppsh)
  453. {
  454. if (hpage && (ppsh->nPages < MAX_PAGES))
  455. {
  456. ppsh->phpage[ppsh->nPages++] = hpage;
  457. return TRUE;
  458. }
  459. }
  460. return FALSE;
  461. }
  462. static int
  463. GetClInt( const TCHAR *p )
  464. {
  465. BOOL neg = FALSE;
  466. int v = 0;
  467. while( *p == TEXT(' ') )
  468. p++; // skip spaces
  469. if( *p == TEXT('-') ) // is it negative?
  470. {
  471. neg = TRUE; // yes, remember that
  472. p++; // skip '-' char
  473. }
  474. // parse the absolute portion
  475. while( ( *p >= TEXT('0') ) && ( *p <= TEXT('9') ) ) // digits only
  476. v = v * 10 + *p++ - TEXT('0'); // accumulate the value
  477. return ( neg? -v : v ); // return the result
  478. }
  479. BOOL CheckRestrictionPage(const PAGEINFO * pPageInfo)
  480. {
  481. BOOL fRestricted = SHRestricted(pPageInfo->dwPolicy1);
  482. if (!fRestricted && pPageInfo->dwPolicy2)
  483. {
  484. fRestricted = SHRestricted(pPageInfo->dwPolicy2);
  485. }
  486. return fRestricted;
  487. }
  488. ///////////////////////////////////////////////////////////////////////////////
  489. // CreateReplaceableHPSXA creates a new hpsxa that contains only the
  490. // interfaces with valid ReplacePage methods.
  491. // APPCOMPAT - EzDesk only implemented AddPages. ReplacePage is NULL for them.
  492. ///////////////////////////////////////////////////////////////////////////////
  493. typedef struct {
  494. UINT count, alloc;
  495. IShellPropSheetExt *interfaces[0];
  496. } PSXA;
  497. HPSXA
  498. CreateReplaceableHPSXA(HPSXA hpsxa)
  499. {
  500. PSXA *psxa = (PSXA *)hpsxa;
  501. DWORD cb = SIZEOF(PSXA) + SIZEOF(IShellPropSheetExt *) * psxa->alloc;
  502. PSXA *psxaRet = (PSXA *)LocalAlloc(LPTR, cb);
  503. if (psxaRet)
  504. {
  505. UINT i;
  506. psxaRet->count = 0;
  507. psxaRet->alloc = psxa->alloc;
  508. for (i=0; i<psxa->count; i++)
  509. {
  510. if (psxa->interfaces[i])
  511. {
  512. psxaRet->interfaces[psxaRet->count++] = psxa->interfaces[i];
  513. }
  514. }
  515. }
  516. return (HPSXA)psxaRet;
  517. }
  518. BOOL HideBackgroundTabOnTermServices(void)
  519. {
  520. BOOL fHideThisPage = FALSE;
  521. TCHAR szSessionName[WINSTATIONNAME_LENGTH * 2];
  522. TCHAR szWallPaper[MAX_PATH*2];
  523. TCHAR szBuf[MAX_PATH*2];
  524. TCHAR szActualValue[MAX_PATH*2];
  525. DWORD dwLen;
  526. DWORD i;
  527. ZeroMemory((PVOID)szSessionName,sizeof(szSessionName));
  528. dwLen = GetEnvironmentVariable(TEXT("SESSIONNAME"), szSessionName, ARRAYSIZE(szSessionName));
  529. if (dwLen != 0)
  530. {
  531. // Now that we have the session name, search for the # character.
  532. for(i = 0; i < dwLen; i++)
  533. {
  534. if (szSessionName[i] == TEXT('#'))
  535. {
  536. szSessionName[i] = TEXT('\0');
  537. break;
  538. }
  539. }
  540. // Here is what we are looking for in NT5:
  541. // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\
  542. // WinStations\RDP-Tcp\UserOverride\Control Panel\Desktop
  543. //
  544. // The value is:
  545. // Wallpaper
  546. //
  547. lstrcpy(szWallPaper,WALLPAPER);
  548. lstrcpy(szBuf, WINSTATION_REG_NAME );
  549. lstrcat(szBuf, L"\\" );
  550. lstrcat(szBuf, szSessionName );
  551. lstrcat(szBuf, L"\\" );
  552. lstrcat(szBuf, WIN_USEROVERRIDE );
  553. lstrcat(szBuf, L"\\" );
  554. lstrcat(szBuf, REGSTR_PATH_DESKTOP ); // Control Panel\\Desktop
  555. // See if we can get the wallpaper string. This will fail if the key
  556. // doesn't exist. This means the policy isn't set.
  557. //
  558. // hKey, lpszSubkey, lpszValueName, lpszDefault,
  559. if (GetStringFromReg(HKEY_LOCAL_MACHINE, szBuf, szWallPaper, TEXT(""),
  560. // lpszValue, cchSizeofValueBuff)
  561. szActualValue, ARRAYSIZE(szActualValue)))
  562. {
  563. fHideThisPage = TRUE;
  564. }
  565. }
  566. return fHideThisPage;
  567. }
  568. HRESULT AddPropSheetExtArrayToThemePageUI(IThemeUIPages * pThemeUI, HPSXA hpsxa)
  569. {
  570. HRESULT hr = E_INVALIDARG;
  571. if (pThemeUI && hpsxa)
  572. {
  573. PSXA *psxa = (PSXA *)hpsxa;
  574. IShellPropSheetExt **spsx = psxa->interfaces;
  575. UINT nIndex;
  576. for (nIndex = 0; nIndex < psxa->count; nIndex++)
  577. {
  578. if (psxa->interfaces[nIndex])
  579. {
  580. IBasePropPage * pBasePropPage;
  581. if (SUCCEEDED(psxa->interfaces[nIndex]->QueryInterface(IID_PPV_ARG(IBasePropPage, &pBasePropPage))))
  582. {
  583. pThemeUI->AddBasePage(pBasePropPage);
  584. pBasePropPage->Release();
  585. }
  586. }
  587. }
  588. }
  589. return hr;
  590. }
  591. /*****************************************************************************\
  592. DESCRIPTION:
  593. If the caller gave the page index, we need to open to that page. The
  594. order of the pages has changed from Win2k to Whistler, so map the indexes.
  595. Win2K:
  596. Index 0: Background
  597. Index 1: Screen Saver
  598. Index 2: Appearance
  599. None: Web
  600. None: Effects
  601. Index 3: Settings (Index 3)
  602. Whistler: (Base Dlg)
  603. None: Themes
  604. Index 0: Background
  605. Index 1: Screen Saver
  606. Index 2: Appearance
  607. Index 3: Settings
  608. Whistler: (Adv Dlg)
  609. None: Themes Settings
  610. None: Adv Appearance
  611. None: Web
  612. None: Effects
  613. \*****************************************************************************/
  614. int UpgradeStartPageMappping(LPTSTR pszCmdLine, DWORD cchSize)
  615. {
  616. int nNewStartPage = GetClInt(pszCmdLine);
  617. if (pszCmdLine)
  618. {
  619. switch (nNewStartPage)
  620. {
  621. case 0: // Background
  622. StrCpyN(pszCmdLine, TEXT("@Desktop"), cchSize);
  623. break;
  624. case 1: // Screen Saver
  625. StrCpyN(pszCmdLine, TEXT("@ScreenSaver"), cchSize);
  626. break;
  627. case 2: // Screen Saver
  628. StrCpyN(pszCmdLine, TEXT("@ScreenSaver"), cchSize);
  629. break;
  630. case 3: // Settings
  631. StrCpyN(pszCmdLine, TEXT("@Settings"), cchSize);
  632. break;
  633. default:
  634. return nNewStartPage;
  635. break;
  636. }
  637. }
  638. else
  639. {
  640. return nNewStartPage;
  641. }
  642. return 0;
  643. }
  644. #define DestroyReplaceableHPSXA(hpsxa) LocalFree((HLOCAL)hpsxa)
  645. /*****************************************************************************\
  646. *
  647. * DeskShowPropSheet( HWND hwndParent )
  648. *
  649. \*****************************************************************************/
  650. typedef HRESULT (*LPFNCOINIT)(LPVOID);
  651. typedef HRESULT (*LPFNCOUNINIT)(void);
  652. int ComputeNumberOfDisplayDevices();
  653. void DeskShowPropSheet(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  654. {
  655. CDisplayControlPanel displayCPL;
  656. displayCPL.DisplayDialog(hInst, hwndParent, pszCmdline);
  657. }
  658. //===========================
  659. // *** IUnknown Interface ***
  660. //===========================
  661. ULONG CDisplayControlPanel::AddRef()
  662. {
  663. return InterlockedIncrement(&m_cRef);
  664. }
  665. ULONG CDisplayControlPanel::Release()
  666. {
  667. if (InterlockedDecrement(&m_cRef))
  668. {
  669. if ((1 == m_cRef) && m_hBackgroundThreads)
  670. {
  671. SetEvent(m_hBackgroundThreads);
  672. }
  673. return m_cRef;
  674. }
  675. delete this;
  676. return 0;
  677. }
  678. HRESULT CDisplayControlPanel::QueryInterface(REFIID riid, void **ppvObj)
  679. {
  680. HRESULT hr = E_NOINTERFACE;
  681. static const QITAB qit[] = {
  682. QITABENT(CDisplayControlPanel, IObjectWithSite),
  683. { 0 },
  684. };
  685. return QISearch(this, qit, riid, ppvObj);
  686. }
  687. CDisplayControlPanel::CDisplayControlPanel(void) : m_cRef(1)
  688. {
  689. m_hBackgroundThreads = NULL;
  690. }
  691. CDisplayControlPanel::~CDisplayControlPanel(void)
  692. {
  693. if (m_hBackgroundThreads)
  694. {
  695. CloseHandle(m_hBackgroundThreads);
  696. m_hBackgroundThreads = NULL;
  697. }
  698. }
  699. // Wait 30 seconds for hung apps to process our message before we give up.
  700. // It would be nice to wait longer, but if the user tries to launch the Display
  701. // Control Panel again, it will not launch because we are still running. The only
  702. // thing that we will give up on doing after 30 seconds it notifying apps. In the worse
  703. // case the user will need to log-off and back in to get apps to refresh.
  704. #define MAX_WAITFORHUNGAPPS (30)
  705. void CDisplayControlPanel::DisplayDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  706. {
  707. if (SUCCEEDED(CoInitialize(NULL)))
  708. {
  709. SHSetInstanceExplorer(SAFECAST(this, IUnknown *));
  710. _ShowDialog(hInst, hwndParent, pszCmdline);
  711. // Wait until the background threads finish.
  712. if (m_cRef > 1)
  713. {
  714. m_hBackgroundThreads = CreateEvent(NULL, FALSE, FALSE, NULL);
  715. if (m_hBackgroundThreads && (m_cRef > 1))
  716. {
  717. DWORD dwResult = SHProcessMessagesUntilEvent(NULL, m_hBackgroundThreads, (MAX_WAITFORHUNGAPPS * 1000));
  718. if (WAIT_TIMEOUT == dwResult)
  719. {
  720. TraceMsg(TF_GENERAL, "A thread hung and we needed to shutdown while it was still running.");
  721. }
  722. Sleep(100);
  723. }
  724. }
  725. SHSetInstanceExplorer(NULL);
  726. CoUninitialize();
  727. }
  728. }
  729. void CDisplayControlPanel::_ShowDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR pszCmdline)
  730. {
  731. HPROPSHEETPAGE hpsp, ahPages[MAX_PAGES];
  732. HPSXA hpsxa = NULL;
  733. PROPSHEETPAGE psp;
  734. PROPSHEETHEADER psh;
  735. int i;
  736. DWORD exitparam = 0UL;
  737. HRESULT hr = S_OK;
  738. TCHAR szCmdLine[MAX_PATH];
  739. StrCpyN(szCmdLine, (pszCmdline ? pszCmdline : TEXT("")), ARRAYSIZE(szCmdLine));
  740. // check if whole sheet is locked out
  741. if (SHRestricted(REST_NODISPLAYCPL))
  742. {
  743. TCHAR szMessage[255],szTitle[255];
  744. LoadString( hInst, IDS_DISPLAY_DISABLED, szMessage, ARRAYSIZE(szMessage) );
  745. LoadString( hInst, IDS_DISPLAY_TITLE, szTitle, ARRAYSIZE(szTitle) );
  746. MessageBox( hwndParent, szMessage, szTitle, MB_OK | MB_ICONINFORMATION );
  747. return;
  748. }
  749. // Create the property sheet
  750. ZeroMemory(&psh, sizeof(psh));
  751. psh.dwSize = sizeof(PROPSHEETHEADER);
  752. psh.dwFlags = (PSH_PROPTITLE | PSH_USECALLBACK);
  753. psh.hwndParent = hwndParent;
  754. psh.hInstance = hInst;
  755. psh.pszCaption = MAKEINTRESOURCE(IDS_DISPLAY_TITLE);
  756. psh.nPages = 0;
  757. psh.phpage = ahPages;
  758. psh.nStartPage = 0;
  759. psh.pfnCallback = NULL;
  760. if (szCmdLine && szCmdLine[0] && (TEXT('@') != szCmdLine[0]))
  761. {
  762. psh.nStartPage = UpgradeStartPageMappping(szCmdLine, ARRAYSIZE(szCmdLine)); // We changed the order so do the mapping
  763. }
  764. ZeroMemory( &psp, sizeof(psp) );
  765. psp.dwSize = sizeof(psp);
  766. psp.dwFlags = PSP_DEFAULT;
  767. psp.hInstance = hInst;
  768. // Build the property sheet. If we are under setup, then just include
  769. // the "settings" page, and no otheres
  770. if (!g_pThemeUI)
  771. {
  772. // CoCreate Themes, Appearance, and Advanced Appearance tabs
  773. hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &g_pThemeUI));
  774. }
  775. if (SUCCEEDED(hr))
  776. {
  777. DWORD dwExecMode;
  778. if (g_pThemeUI && (SUCCEEDED(g_pThemeUI->GetExecMode(&dwExecMode))) && (dwExecMode == EM_NORMAL))
  779. {
  780. if (!GetSystemMetrics(SM_CLEANBOOT))
  781. {
  782. hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE,
  783. REGSTR_PATH_CONTROLSFOLDER TEXT("\\Desk"), 8);
  784. }
  785. for (i = 0; i < C_PAGES_DESK; i++)
  786. {
  787. BOOL fHideThisPage = FALSE;
  788. if (CheckRestrictionPage(&aPageInfo[i]))
  789. {
  790. // This page is locked out by admin, don't put it up
  791. fHideThisPage = TRUE;
  792. }
  793. // For Terminal Services, we need to hide the Background tab if a machine
  794. // policy is set to not allow wallpaper changes for this session.
  795. if ((aPageInfo[i].pfnDlgProc == BackgroundDlgProc) &&
  796. GetSystemMetrics(SM_REMOTESESSION) &&
  797. !fHideThisPage)
  798. {
  799. fHideThisPage = HideBackgroundTabOnTermServices();
  800. }
  801. if (-1 == aPageInfo[i].nExtensionID)
  802. {
  803. psp.pszTemplate = MAKEINTRESOURCE(aPageInfo[i].id);
  804. psp.pfnDlgProc = aPageInfo[i].pfnDlgProc;
  805. psp.dwFlags = PSP_DEFAULT;
  806. psp.lParam = 0L;
  807. if (!fHideThisPage && (psp.pfnDlgProc == BackgroundDlgProc))
  808. {
  809. // This page can be overridden by extensions
  810. if( hpsxa )
  811. {
  812. UINT cutoff = psh.nPages;
  813. UINT added = 0;
  814. HPSXA hpsxaReplace = CreateReplaceableHPSXA(hpsxa);
  815. if (hpsxaReplace)
  816. {
  817. added = SHReplaceFromPropSheetExtArray( hpsxaReplace, CPLPAGE_DISPLAY_BACKGROUND,
  818. _AddDisplayPropSheetPage, (LPARAM)&psh);
  819. DestroyReplaceableHPSXA(hpsxaReplace);
  820. }
  821. if (added)
  822. {
  823. if (psh.nStartPage >= cutoff)
  824. psh.nStartPage += added-1;
  825. continue;
  826. }
  827. }
  828. }
  829. if (!fHideThisPage && (hpsp = CreatePropertySheetPage(&psp)))
  830. {
  831. psh.phpage[psh.nPages++] = hpsp;
  832. }
  833. }
  834. else if (g_pThemeUI && !fHideThisPage)
  835. {
  836. IBasePropPage * pBasePage = NULL;
  837. // add extensions from the registry
  838. // CAUTION: Do not check for "fHideThisPage" here. We need to add the pages for
  839. // property sheet extensions even if the "Settings" page is hidden.
  840. if (i == IPI_SETTINGS && hpsxa)
  841. {
  842. UINT cutoff = psh.nPages;
  843. UINT added = SHAddFromPropSheetExtArray(hpsxa, _AddDisplayPropSheetPage, (LPARAM)&psh);
  844. if (psh.nStartPage >= cutoff)
  845. psh.nStartPage += added;
  846. }
  847. switch (aPageInfo[i].id)
  848. {
  849. case 0:
  850. hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[i].nExtensionID);
  851. break;
  852. case DLG_SCREENSAVER:
  853. hr = CoCreateInstance(CLSID_ScreenSaverPage, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage));
  854. break;
  855. case DLG_BACKGROUND:
  856. hr = CoCreateInstance(CLSID_CDeskHtmlProp, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBasePropPage, &pBasePage));
  857. break;
  858. default:
  859. AssertMsg(0, TEXT("The value must be specified"));
  860. break;
  861. };
  862. if (pBasePage)
  863. {
  864. IShellPropSheetExt * pspse = NULL;
  865. // If they implement IShellPropSheetExt, then add their base pages.
  866. if (SUCCEEDED(pBasePage->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse))))
  867. {
  868. hr = pspse->AddPages(_AddDisplayPropSheetPage, (LPARAM)&psh);
  869. pspse->Release();
  870. }
  871. hr = g_pThemeUI->AddBasePage(pBasePage);
  872. pBasePage->Release();
  873. }
  874. }
  875. }
  876. if (hpsxa)
  877. {
  878. // Have the dynamically added pages added to IThemeUIPages.
  879. AddPropSheetExtArrayToThemePageUI(g_pThemeUI, hpsxa);
  880. }
  881. // add a fake settings page to fool OEM extensions
  882. // !!! this page must be last !!!
  883. if (hpsxa)
  884. {
  885. g_pThemeUI->AddFakeSettingsPage((LPVOID)&psh);
  886. }
  887. }
  888. else
  889. {
  890. // For the SETUP case, only the display page should show up.
  891. hr = g_pThemeUI->AddPage(_AddDisplayPropSheetPage, (LPARAM)&psh, aPageInfo[IPI_SETTINGS].nExtensionID);
  892. }
  893. if (psh.nStartPage >= psh.nPages)
  894. psh.nStartPage = 0;
  895. if (psh.nPages)
  896. {
  897. DWORD dwAction = DESKACTION_NONE;
  898. TCHAR szStartPage[MAX_PATH];
  899. WCHAR szOpenPath[MAX_PATH];
  900. IPropertyBag * pPropertyBag;
  901. SetStartPage(&psh, szCmdLine, &dwAction, szOpenPath, ARRAYSIZE(szOpenPath), szStartPage, ARRAYSIZE(szStartPage));
  902. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IPropertyBag, &pPropertyBag));
  903. if (SUCCEEDED(hr))
  904. {
  905. VARIANT var;
  906. if (DESKACTION_NONE != dwAction)
  907. {
  908. var.vt = VT_LPWSTR;
  909. var.bstrVal = szOpenPath;
  910. hr = pPropertyBag->Write(((DESKACTION_OPENTHEME == dwAction) ? SZ_PBPROP_THEME_LAUNCHTHEME : SZ_PBPROP_APPEARANCE_LAUNCHMSTHEME), &var);
  911. }
  912. // The following SZ_PBPROP_PREOPEN call will save a "Custom.theme" so users can always go back to
  913. // their settings if they don't like changes they make in the CPL.
  914. pPropertyBag->Write(SZ_PBPROP_PREOPEN, NULL);
  915. pPropertyBag->Release();
  916. }
  917. if (PropertySheet(&psh) == ID_PSRESTARTWINDOWS)
  918. {
  919. exitparam = EWX_REBOOT;
  920. }
  921. }
  922. if (g_pThemeUI)
  923. {
  924. IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
  925. g_pThemeUI->Release();
  926. g_pThemeUI = NULL;
  927. }
  928. // free any loaded extensions
  929. if (hpsxa)
  930. {
  931. SHDestroyPropSheetExtArray(hpsxa);
  932. }
  933. if (exitparam == EWX_REBOOT)
  934. {
  935. RestartDialogEx(hwndParent, NULL, exitparam, (SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_RECONFIG));
  936. }
  937. }
  938. return;
  939. }
  940. DWORD gdwCoverStyle = WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
  941. #if 0 // This code creates another thread for the cover window, which we don't really need
  942. // and is causing a problem. I am not sure if this is needed for NT, so leave it here....
  943. ///////////////////////////////////////////////////////////////////////////////
  944. //
  945. // CreateCoverWindow
  946. //
  947. // creates a window which obscures the display
  948. // flags:
  949. // 0 means erase to black
  950. // COVER_NOPAINT means "freeze" the display
  951. //
  952. // just post it a WM_CLOSE when you're done with it
  953. //
  954. ///////////////////////////////////////////////////////////////////////////////
  955. typedef struct {
  956. DWORD flags;
  957. HWND hwnd;
  958. HANDLE heRetvalSet;
  959. } CVRWNDPARM, * PCVRWNDPARM;
  960. DWORD WINAPI CreateCoverWindowThread( LPVOID pv )
  961. {
  962. PCVRWNDPARM pcwp = (PCVRWNDPARM)pv;
  963. MSG msg;
  964. pcwp->hwnd = CreateWindowEx( gdwCoverStyle,
  965. sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | pcwp->flags, 0, 0,
  966. GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ),
  967. NULL, NULL, hInstance, NULL );
  968. if( pcwp->hwnd )
  969. {
  970. SetForegroundWindow( pcwp->hwnd );
  971. UpdateWindow( pcwp->hwnd );
  972. }
  973. // return wnd;
  974. SetEvent(pcwp->heRetvalSet);
  975. /* Acquire and dispatch messages until a WM_QUIT message is received. */
  976. while (GetMessage(&msg, NULL, 0L, 0L)) {
  977. TranslateMessage(&msg);
  978. DispatchMessage(&msg);
  979. }
  980. ExitThread(0);
  981. return 0;
  982. }
  983. void DestroyCoverWindow(HWND hwndCover)
  984. {
  985. if (hwndCover)
  986. PostMessage(hwndCover, WM_CLOSE, 0, 0L);
  987. }
  988. HWND FAR PASCAL
  989. CreateCoverWindow( DWORD flags )
  990. {
  991. CVRWNDPARM cwp;
  992. HANDLE hThread;
  993. DWORD idTh;
  994. DWORD dwWaitResult = 0;
  995. // Init params
  996. cwp.flags = flags;
  997. cwp.hwnd = NULL;
  998. cwp.heRetvalSet = CreateEvent(NULL, TRUE, FALSE, NULL);
  999. if (cwp.heRetvalSet == NULL)
  1000. return NULL;
  1001. // CreateThread
  1002. hThread = CreateThread(NULL, 0, CreateCoverWindowThread, &cwp, 0, &idTh);
  1003. CloseHandle(hThread);
  1004. // Wait for Thread to return the handle to us
  1005. do
  1006. {
  1007. dwWaitResult = MsgWaitForMultipleObjects(1,
  1008. &cwp.heRetvalSet,
  1009. FALSE,
  1010. INFINITE,
  1011. QS_ALLINPUT);
  1012. switch(dwWaitResult)
  1013. {
  1014. case WAIT_OBJECT_0 + 1:
  1015. {
  1016. MSG msg ;
  1017. //
  1018. // Allow blocked thread to respond to sent messages.
  1019. //
  1020. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1021. {
  1022. if ( WM_QUIT != msg.message )
  1023. {
  1024. TranslateMessage(&msg);
  1025. DispatchMessage(&msg);
  1026. }
  1027. else
  1028. {
  1029. //
  1030. // Received WM_QUIT.
  1031. // Don't wait for event.
  1032. //
  1033. dwWaitResult = WAIT_FAILED;
  1034. }
  1035. }
  1036. break;
  1037. }
  1038. default:
  1039. break;
  1040. }
  1041. }
  1042. while((WAIT_OBJECT_0 + 1) == dwWaitResult);
  1043. CloseHandle(cwp.heRetvalSet);
  1044. return cwp.hwnd;
  1045. }
  1046. #endif
  1047. void DestroyCoverWindow(HWND hwndCover)
  1048. {
  1049. DestroyWindow(hwndCover);
  1050. }
  1051. HWND FAR PASCAL CreateCoverWindow( DWORD flags )
  1052. {
  1053. HWND hwndCover = CreateWindowEx( gdwCoverStyle,
  1054. sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | flags,
  1055. GetSystemMetrics( SM_XVIRTUALSCREEN ),
  1056. GetSystemMetrics( SM_YVIRTUALSCREEN ),
  1057. GetSystemMetrics( SM_CXVIRTUALSCREEN ),
  1058. GetSystemMetrics( SM_CYVIRTUALSCREEN ),
  1059. NULL, NULL, hInstance, NULL );
  1060. if( hwndCover )
  1061. {
  1062. SetForegroundWindow( hwndCover );
  1063. if (flags & COVER_NOPAINT)
  1064. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1065. UpdateWindow( hwndCover);
  1066. }
  1067. return hwndCover;
  1068. }
  1069. ///////////////////////////////////////////////////////////////////////////////
  1070. // CoverWndProc (see CreateCoverWindow)
  1071. ///////////////////////////////////////////////////////////////////////////////
  1072. #define WM_PRIV_KILL_LATER (WM_APP + 100) //Private message to kill ourselves later.
  1073. LRESULT CALLBACK
  1074. CoverWindowProc( HWND window, UINT message, WPARAM wparam, LPARAM lparam )
  1075. {
  1076. switch( message )
  1077. {
  1078. case WM_CREATE:
  1079. SetTimer( window, ID_CVRWND_TIMER, CMSEC_COVER_WINDOW_TIMEOUT, NULL );
  1080. break;
  1081. case WM_TIMER:
  1082. // Times up... Shut ourself down
  1083. if (wparam == ID_CVRWND_TIMER)
  1084. DestroyWindow(window);
  1085. break;
  1086. case WM_ERASEBKGND:
  1087. // NOTE: assumes our class brush is the NULL_BRUSH stock object
  1088. if( !( GetWindowLong( window, GWL_STYLE ) & COVER_NOPAINT ) )
  1089. {
  1090. HDC dc = (HDC)wparam;
  1091. RECT rc;
  1092. if( GetClipBox( dc, (LPRECT)&rc ) != NULLREGION )
  1093. {
  1094. FillRect( dc, (LPRECT)&rc, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
  1095. // HACK: make sure fillrect is done before we return
  1096. // this is to better hide flicker during dynares-crap
  1097. GetPixel( dc, rc.left + 1, rc.top + 1 );
  1098. }
  1099. }
  1100. break;
  1101. // We post a private message to ourselves because:
  1102. // When WM_CLOSE is processed by this window, it calls DestroyWindow() which results in
  1103. // WM_ACTIVATE (WA_INACTIVE) message to be sent to this window. If this code calls
  1104. // DestroyWindow again, it causes a loop. So, instead of calling DestroyWindow immediately,
  1105. // we post ourselves a message and destroy us letter.
  1106. case WM_ACTIVATE:
  1107. if( GET_WM_ACTIVATE_STATE( wparam, lparam ) == WA_INACTIVE )
  1108. {
  1109. PostMessage( window, WM_PRIV_KILL_LATER, 0L, 0L );
  1110. return 1L;
  1111. }
  1112. break;
  1113. case WM_PRIV_KILL_LATER:
  1114. DestroyWindow(window);
  1115. break;
  1116. case WM_DESTROY:
  1117. KillTimer(window, ID_CVRWND_TIMER);
  1118. break;
  1119. }
  1120. return DefWindowProc( window, message, wparam, lparam );
  1121. }
  1122. BOOL _FindCoverWindowCallback(HWND hwnd, LPARAM lParam)
  1123. {
  1124. TCHAR szClass[MAX_PATH];
  1125. HWND *phwnd = (HWND*)lParam;
  1126. if( !GetClassName(hwnd, szClass, ARRAYSIZE(szClass)) )
  1127. return TRUE;
  1128. if( StrCmp(szClass, sc_szCoverClass) == 0 )
  1129. {
  1130. if( phwnd )
  1131. *phwnd = hwnd;
  1132. return FALSE;
  1133. }
  1134. return TRUE;
  1135. }
  1136. BYTE WINAPI MyStrToByte(LPCTSTR sz)
  1137. {
  1138. BYTE l=0;
  1139. while (*sz >= TEXT('0') && *sz <= TEXT('9'))
  1140. {
  1141. l = l*10 + (*sz++ - TEXT('0'));
  1142. }
  1143. return l;
  1144. }
  1145. COLORREF ConvertColor(LPTSTR lpColor)
  1146. {
  1147. BYTE RGBTemp[3];
  1148. LPTSTR lpTemp = lpColor;
  1149. UINT i;
  1150. if (!lpColor || !*lpColor)
  1151. {
  1152. return RGB(0,0,0);
  1153. }
  1154. for (i =0; i < 3; i++)
  1155. {
  1156. // Remove leading spaces
  1157. while (*lpTemp == TEXT(' '))
  1158. {
  1159. lpTemp++;
  1160. }
  1161. // Set lpColor to the beginning of the number
  1162. lpColor = lpTemp;
  1163. // Find the end of the number and null terminate
  1164. while ((*lpTemp) && (*lpTemp != TEXT(' ')))
  1165. {
  1166. lpTemp++;
  1167. }
  1168. if (*lpTemp != TEXT('\0'))
  1169. {
  1170. *lpTemp = TEXT('\0');
  1171. }
  1172. lpTemp++;
  1173. RGBTemp[i] = MyStrToByte(lpColor);
  1174. }
  1175. return (RGB(RGBTemp[0], RGBTemp[1], RGBTemp[2]));
  1176. }
  1177. LONG APIENTRY CPlApplet(
  1178. HWND hwnd,
  1179. WORD message,
  1180. LPARAM wParam,
  1181. LPARAM lParam)
  1182. {
  1183. LPCPLINFO lpCPlInfo;
  1184. LPNEWCPLINFO lpNCPlInfo;
  1185. HWND hwndCover;
  1186. switch (message)
  1187. {
  1188. case CPL_INIT: // Is any one there ?
  1189. // Init the common controls
  1190. if (!DeskInitCpl())
  1191. return 0;
  1192. // Load ONE string for emergencies.
  1193. LoadString (hInstance, IDS_DISPLAY_TITLE, gszDeskCaption, ARRAYSIZE(gszDeskCaption));
  1194. return !0;
  1195. case CPL_GETCOUNT: // How many applets do you support ?
  1196. return 1;
  1197. case CPL_INQUIRE: // Fill CplInfo structure
  1198. lpCPlInfo = (LPCPLINFO)lParam;
  1199. lpCPlInfo->idIcon = IDI_DISPLAY;
  1200. lpCPlInfo->idName = IDS_NAME;
  1201. lpCPlInfo->idInfo = IDS_INFO;
  1202. lpCPlInfo->lData = 0;
  1203. break;
  1204. case CPL_NEWINQUIRE:
  1205. lpNCPlInfo = (LPNEWCPLINFO)lParam;
  1206. lpNCPlInfo->hIcon = LoadIcon(hInstance, (LPTSTR) MAKEINTRESOURCE(IDI_DISPLAY));
  1207. LoadString(hInstance, IDS_NAME, lpNCPlInfo->szName, ARRAYSIZE(lpNCPlInfo->szName));
  1208. if (!LoadString(hInstance, IDS_INFO, lpNCPlInfo->szInfo, ARRAYSIZE(lpNCPlInfo->szInfo)))
  1209. lpNCPlInfo->szInfo[0] = (TCHAR) 0;
  1210. lpNCPlInfo->dwSize = sizeof( NEWCPLINFO );
  1211. lpNCPlInfo->lData = 0;
  1212. #if 0
  1213. lpNCPlInfo->dwHelpContext = IDH_CHILD_DISPLAY;
  1214. lstrcpy(lpNCPlInfo->szHelpFile, xszControlHlp);
  1215. #else
  1216. lpNCPlInfo->dwHelpContext = 0;
  1217. lstrcpy(lpNCPlInfo->szHelpFile, TEXT(""));
  1218. #endif
  1219. return TRUE;
  1220. case CPL_DBLCLK: // You have been chosen to run
  1221. /*
  1222. * One of your applets has been double-clicked.
  1223. * wParam is an index from 0 to (NUM_APPLETS-1)
  1224. * lParam is the lData value associated with the applet
  1225. */
  1226. lParam = 0L;
  1227. // fall through...
  1228. case CPL_STARTWPARMS:
  1229. DeskShowPropSheet( hInstance, hwnd, (LPTSTR)lParam );
  1230. // ensure that any cover windows we've created have been destroyed
  1231. do
  1232. {
  1233. hwndCover = 0;
  1234. EnumWindows( _FindCoverWindowCallback, (LPARAM)&hwndCover );
  1235. if( hwndCover )
  1236. {
  1237. DestroyWindow( hwndCover );
  1238. }
  1239. }
  1240. while( hwndCover );
  1241. return TRUE; // Tell RunDLL.exe that I succeeded
  1242. case CPL_EXIT: // You must really die
  1243. if (g_hdcMem)
  1244. {
  1245. ReleaseDC(NULL, g_hdcMem);
  1246. g_hdcMem = NULL;
  1247. }
  1248. // Fall thru...
  1249. case CPL_STOP: // You must die
  1250. if (g_pThemeUI)
  1251. {
  1252. IUnknown_SetSite(g_pThemeUI, NULL); // Tell him to break the ref-count cycle with his children.
  1253. g_pThemeUI->Release();
  1254. g_pThemeUI = NULL;
  1255. }
  1256. break;
  1257. case CPL_SELECT: // You have been selected
  1258. /*
  1259. * Sent once for each applet prior to the CPL_EXIT msg.
  1260. * wParam is an index from 0 to (NUM_APPLETS-1)
  1261. * lParam is the lData value associated with the applet
  1262. */
  1263. break;
  1264. //
  1265. // Private message sent when this applet is running under "Setup"
  1266. //
  1267. case CPL_SETUP:
  1268. if (g_pThemeUI)
  1269. {
  1270. g_pThemeUI->SetExecMode(EM_SETUP);
  1271. }
  1272. break;
  1273. // Private message used by userenv.dll to refresh the display colors
  1274. case CPL_POLICYREFRESH:
  1275. if (g_pThemeUI) // If this object doesn't exist, then we don't need to refresh anything.
  1276. {
  1277. IPreviewSystemMetrics * ppsm;
  1278. if (SUCCEEDED(g_pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm))))
  1279. {
  1280. ppsm->RefreshColors();
  1281. ppsm->Release();
  1282. }
  1283. }
  1284. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, FALSE);
  1285. break;
  1286. }
  1287. return 0L;
  1288. }
  1289. BOOL WINAPI DeskSetCurrentSchemeW(IN LPCWSTR pwzSchemeName)
  1290. {
  1291. BOOL fSuccess = FALSE;
  1292. IThemeUIPages * pThemeUI = NULL;
  1293. HRESULT hr;
  1294. HRESULT hrOle = SHCoInitialize();
  1295. if (g_pThemeUI)
  1296. {
  1297. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1298. }
  1299. else
  1300. {
  1301. hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1302. }
  1303. if (SUCCEEDED(hr))
  1304. {
  1305. IPreviewSystemMetrics * ppsm;
  1306. hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm));
  1307. if (SUCCEEDED(hr))
  1308. {
  1309. hr = ppsm->DeskSetCurrentScheme(pwzSchemeName);
  1310. ppsm->Release();
  1311. }
  1312. fSuccess = SUCCEEDED(hr);
  1313. pThemeUI->Release();
  1314. }
  1315. SHCoUninitialize(hrOle);
  1316. return fSuccess;
  1317. }
  1318. //------------------------------------------------------------------------------------------------
  1319. // This function gets the current DPI, reads the last updated DPI from registry and compares
  1320. // these two. If these two are equal, it returns immediately.
  1321. // If these two DPI values are different, then it updates the size of UI fonts to reflect the
  1322. // change in the DPI values.
  1323. //
  1324. // This function is called from explorer sothat when DPI value is changed by admin and then every
  1325. // other user who logs-in gets this change.
  1326. //------------------------------------------------------------------------------------------------
  1327. void WINAPI UpdateUIfontsDueToDPIchange(int iOldDPI, int iNewDPI)
  1328. {
  1329. BOOL fSuccess = FALSE;
  1330. IThemeManager * pThemeMgr = NULL;
  1331. HRESULT hr;
  1332. HRESULT hrOle = SHCoInitialize();
  1333. if (g_pThemeUI)
  1334. {
  1335. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeManager, &pThemeMgr));
  1336. }
  1337. else
  1338. {
  1339. hr = CoCreateInstance(CLSID_ThemeManager, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeManager, &pThemeMgr));
  1340. }
  1341. if (SUCCEEDED(hr))
  1342. {
  1343. IPropertyBag * pPropertyBag;
  1344. hr = GetPageByCLSID(pThemeMgr, &PPID_BaseAppearance, &pPropertyBag);
  1345. if (SUCCEEDED(hr))
  1346. {
  1347. 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.
  1348. hr = SHPropertyBag_WriteInt(pPropertyBag, SZ_PBPROP_DPI_MODIFIED_VALUE, iNewDPI);
  1349. if (SUCCEEDED(hr))
  1350. {
  1351. hr = pThemeMgr->ApplyNow();
  1352. }
  1353. pPropertyBag->Release();
  1354. }
  1355. fSuccess = SUCCEEDED(hr);
  1356. pThemeMgr->Release();
  1357. }
  1358. SHCoUninitialize(hrOle);
  1359. }
  1360. BOOL DeskSetCurrentSchemeA(IN LPCSTR pszSchemeName)
  1361. {
  1362. WCHAR wzSchemeName[MAX_PATH];
  1363. MultiByteToWideChar(CP_ACP, 0, pszSchemeName, -1, wzSchemeName, ARRAYSIZE(wzSchemeName));
  1364. return DeskSetCurrentSchemeW(wzSchemeName);
  1365. }
  1366. STDAPI UpdateCharsetChanges(void)
  1367. {
  1368. BOOL fSuccess = FALSE;
  1369. IThemeUIPages * pThemeUI = NULL;
  1370. HRESULT hr;
  1371. HRESULT hrOle = SHCoInitialize();
  1372. if (g_pThemeUI)
  1373. {
  1374. hr = g_pThemeUI->QueryInterface(IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1375. }
  1376. else
  1377. {
  1378. hr = CoCreateInstance(CLSID_ThemeUIPages, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IThemeUIPages, &pThemeUI));
  1379. }
  1380. if (SUCCEEDED(hr))
  1381. {
  1382. IPreviewSystemMetrics * ppsm;
  1383. hr = pThemeUI->QueryInterface(IID_PPV_ARG(IPreviewSystemMetrics, &ppsm));
  1384. if (SUCCEEDED(hr))
  1385. {
  1386. hr = ppsm->UpdateCharsetChanges();
  1387. ppsm->Release();
  1388. }
  1389. pThemeUI->Release();
  1390. }
  1391. SHCoUninitialize(hrOle);
  1392. return hr;
  1393. }