desk.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 36k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "precomp.h"
  2. #include "winuser.h"
  3. #ifdef WINNT
  4. #include <regapi.h>
  5. #include <ctxdef.h> // hydra stuff
  6. #endif
  7. #pragma hdrstop
  8. #include "cplext.h"
  9. #include "cplp.h"
  10. ///////////////////////////////////////////////////////////////////////////////
  11. // Array defining each page in the sheet
  12. ///////////////////////////////////////////////////////////////////////////////
  13. typedef struct {
  14.     int id;
  15.     DLGPROC pfnDlgProc;
  16.     LPCTSTR szRegChkName;
  17. } PAGEINFO;
  18. PAGEINFO aPageInfo[] = {
  19.     { DLG_BACKGROUND,   BackgroundDlgProc,   REGSTR_VAL_DISPCPL_NOBACKGROUNDPAGE },
  20.     { DLG_SCREENSAVER,  ScreenSaverDlgProc,  REGSTR_VAL_DISPCPL_NOSCRSAVPAGE     },
  21.     { DLG_APPEARANCE,   AppearanceDlgProc,   REGSTR_VAL_DISPCPL_NOAPPEARANCEPAGE },
  22.     { DLG_MULTIMONITOR, MultiMonitorDlgProc, REGSTR_VAL_DISPCPL_NOSETTINGSPAGE   },
  23. };
  24. #define C_PAGES_DESK    ARRAYSIZE(aPageInfo)
  25. #define IPI_SETTINGS    (C_PAGES_DESK-1)        // Index to "Settings" page
  26. #define WALLPAPER     L"Wallpaper"
  27. /*
  28.  * Local Constant Declarations
  29.  */
  30. static const TCHAR sc_szCoverClass[] = TEXT("DeskSaysNoPeekingItsASurprise");
  31. LRESULT CALLBACK CoverWindowProc( HWND, UINT, WPARAM, LPARAM );
  32. VOID RefreshColors (void);
  33. ///////////////////////////////////////////////////////////////////////////////
  34. // Globals
  35. ///////////////////////////////////////////////////////////////////////////////
  36. TCHAR gszDeskCaption[CCH_MAX_STRING];
  37. TCHAR g_szNULL[] = TEXT("") ;
  38. TCHAR g_szControlIni[] = TEXT("control.ini") ;
  39. TCHAR g_szPatterns[] = TEXT("patterns") ;
  40. TCHAR g_szNone[CCH_NONE];                      // this is the '(None)' string
  41. TCHAR g_szBoot[] = TEXT("boot");
  42. TCHAR g_szSystemIni[] = TEXT("system.ini");
  43. TCHAR g_szWindows[] = TEXT("Windows");
  44. HDC g_hdcMem;
  45. HBITMAP g_hbmDefault;
  46. BOOL g_bMirroredOS = FALSE;
  47. EXEC_MODE gbExecMode = EXEC_NORMAL;
  48. EXEC_INVALID_SUBMODE gbInvalidMode = NOT_INVALID;
  49. ///////////////////////////////////////////////////////////////////////////////
  50. // Externs
  51. ///////////////////////////////////////////////////////////////////////////////
  52. extern BOOL NEAR PASCAL GetStringFromReg(HKEY   hKey,
  53.                                         LPCTSTR lpszSubkey,
  54.                                         LPCTSTR lpszValueName,
  55.                                         LPCTSTR lpszDefault,
  56.                                         LPTSTR lpszValue,
  57.                                         DWORD cchSizeofValueBuff);
  58. /*---------------------------------------------------------
  59. **
  60. **---------------------------------------------------------*/
  61. BOOL NEAR PASCAL CreateGlobals()
  62. {
  63.     WNDCLASS wc;
  64.     HBITMAP hbm;
  65.     HDC hdc;
  66.     //
  67.     // Check if the mirroring APIs exist on the current
  68.     // platform.
  69.     //
  70.     g_bMirroredOS = IS_MIRRORING_ENABLED();
  71.     if( !GetClassInfo( hInstance, sc_szCoverClass, &wc ) )
  72.     {
  73.         // if two pages put one up, share one dc
  74.         wc.style = CS_CLASSDC;
  75.         wc.lpfnWndProc = CoverWindowProc;
  76.         wc.cbClsExtra = wc.cbWndExtra = 0;
  77.         wc.hInstance = hInstance;
  78.         wc.hIcon = (HICON)( wc.hCursor = NULL );
  79.         // use a real brush since user will try to paint us when we're "hung"
  80.         wc.hbrBackground = GetStockObject( NULL_BRUSH );
  81.         wc.lpszMenuName = NULL;
  82.         wc.lpszClassName = sc_szCoverClass;
  83.         if( !RegisterClass( &wc ) )
  84.             return FALSE;
  85.     }
  86.     hdc = GetDC(NULL);
  87.     g_hdcMem = CreateCompatibleDC(hdc);
  88.     ReleaseDC(NULL, hdc);
  89.     if (!g_hdcMem)
  90.         return FALSE;
  91.     hbm = CreateBitmap(1, 1, 1, 1, NULL);
  92.     g_hbmDefault = SelectObject(g_hdcMem, hbm);
  93.     SelectObject(g_hdcMem, g_hbmDefault);
  94.     DeleteObject(hbm);
  95.     LoadString(hInstance, IDS_NONE, g_szNone, ARRAYSIZE(g_szNone));
  96.     RegisterBackPreviewClass(hInstance);
  97.     RegisterLookPreviewClass(hInstance);
  98.     return TRUE;
  99. }
  100. /*---------------------------------------------------------
  101. **
  102. **---------------------------------------------------------*/
  103. HBITMAP FAR LoadMonitorBitmap( BOOL bFillDesktop )
  104. {
  105.     HBITMAP hbm,hbmT;
  106.     BITMAP bm;
  107.     HBRUSH hbrT;
  108.     HDC hdc;
  109.     COLORREF c3df = GetSysColor( COLOR_3DFACE );
  110.     hbm = LoadBitmap(hInstance, MAKEINTRESOURCE(BMP_MONITOR));
  111.     if (hbm == NULL)
  112.     {
  113.         //Assert(0);
  114.         return NULL;
  115.     }
  116.     //
  117.     // convert the "base" of the monitor to the right color.
  118.     //
  119.     // the lower left of the bitmap has a transparent color
  120.     // we fixup using FloodFill
  121.     //
  122.     hdc = CreateCompatibleDC(NULL);
  123.     hbmT = SelectObject(hdc, hbm);
  124.     hbrT = SelectObject(hdc, GetSysColorBrush(COLOR_3DFACE));
  125.     GetObject(hbm, sizeof(bm), &bm);
  126.     ExtFloodFill(hdc, 0, bm.bmHeight-1,
  127.         GetPixel(hdc, 0, bm.bmHeight-1), FLOODFILLSURFACE);
  128.     // round off the corners
  129.     // the bottom two were done by the floodfill above
  130.     // the top left is important since SS_CENTERIMAGE uses it to fill gaps
  131.     // the top right should be rounded because the other three are
  132.     SetPixel( hdc, 0, 0, c3df );
  133.     SetPixel( hdc, bm.bmWidth-1, 0, c3df );
  134.     // unless the caller would like to do it, we fill in the desktop here
  135.     if( bFillDesktop )
  136.     {
  137.         SelectObject(hdc, GetSysColorBrush(COLOR_DESKTOP));
  138.         ExtFloodFill(hdc, MON_X+1, MON_Y+1,
  139.             GetPixel(hdc, MON_X+1, MON_Y+1), FLOODFILLSURFACE);
  140.     }
  141.     // clean up after ourselves
  142.     SelectObject(hdc, hbrT);
  143.     SelectObject(hdc, hbmT);
  144.     DeleteDC(hdc);
  145.     return hbm;
  146. }
  147. ///////////////////////////////////////////////////////////////////////////////
  148. //
  149. // Messagebox wrapper
  150. //
  151. //
  152. ///////////////////////////////////////////////////////////////////////////////
  153. int
  154. FmtMessageBox(
  155.     HWND hwnd,
  156.     UINT fuStyle,
  157.     DWORD dwTitleID,
  158.     DWORD dwTextID)
  159. {
  160.     TCHAR Title[256];
  161.     TCHAR Text[2000];
  162.     LoadString(hInstance, dwTextID, Text, SIZEOF(Text));
  163.     LoadString(hInstance, dwTitleID, Title, SIZEOF(Title));
  164.     return (ShellMessageBox(hInstance, hwnd, Text, Title, fuStyle));
  165. }
  166. ///////////////////////////////////////////////////////////////////////////////
  167. //
  168. // InstallScreenSaver
  169. //
  170. // Provides a RUNDLL32-callable routine to install a screen saver
  171. //
  172. ///////////////////////////////////////////////////////////////////////////////
  173. #ifdef UNICODE
  174. //
  175. // Windows NT:
  176. //
  177. // Thunk ANSI version to the Unicode function
  178. //
  179. void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw );
  180. void WINAPI InstallScreenSaverA( HWND wnd, HINSTANCE inst, LPSTR cmd, int shw )
  181. {
  182.     LPWSTR  pwszCmd;
  183.     int     cch;
  184.     cch = MultiByteToWideChar( CP_ACP, 0, cmd, -1, NULL, 0);
  185.     if (cch == 0)
  186.         return;
  187.     pwszCmd = LocalAlloc( LMEM_FIXED, cch * SIZEOF(TCHAR) );
  188.     if (pwszCmd == NULL)
  189.         return;
  190.     MultiByteToWideChar( CP_ACP, 0, cmd, -1, pwszCmd, cch);
  191.     InstallScreenSaverW(wnd, inst, pwszCmd, shw);
  192.     LocalFree(pwszCmd);
  193. }
  194. #   define REAL_INSTALL_SCREEN_SAVER   InstallScreenSaverW
  195. #else
  196. //
  197. // Windows 95:
  198. //
  199. // Stub out Unicode version
  200. //
  201. void WINAPI InstallScreenSaverW( HWND wnd, HINSTANCE inst, LPWSTR cmd, int shw )
  202. {
  203.     SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  204.     return;
  205. }
  206. #   define REAL_INSTALL_SCREEN_SAVER   InstallScreenSaverA
  207. #endif
  208. void WINAPI REAL_INSTALL_SCREEN_SAVER( HWND wnd, HINSTANCE inst, LPTSTR cmd, int shw )
  209. {
  210.     TCHAR buf[ MAX_PATH ];
  211.     int timeout;
  212.     lstrcpy( buf, cmd );
  213.     PathGetShortPath( buf ); // so msscenes doesn't die
  214.     WritePrivateProfileString( TEXT("boot"), TEXT("SCRNSAVE.EXE"), buf, TEXT("system.ini") );
  215.     SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, TRUE, NULL,
  216.         SPIF_UPDATEINIFILE );
  217.     // make sure the user has a non-stupid timeout set
  218.     SystemParametersInfo( SPI_GETSCREENSAVETIMEOUT, 0, &timeout, 0 );
  219.     if( timeout <= 0 )
  220.     {
  221.         // 15 minutes seems like a nice default
  222.         SystemParametersInfo( SPI_SETSCREENSAVETIMEOUT, 900, NULL,
  223.             SPIF_UPDATEINIFILE );
  224.     }
  225.     // bring up the screen saver page on our rundll
  226. #ifdef UNICODE
  227.     Control_RunDLLW( wnd, inst, TEXT("DESK.CPL,,1"), shw );
  228. #else
  229.     Control_RunDLL( wnd, inst, TEXT("DESK.CPL,,1"), shw );
  230. #endif
  231. }
  232. /*****************************************************************************
  233. *
  234. * DeskInitCpl( void )
  235. *
  236. *****************************************************************************/
  237. BOOL DeskInitCpl(void) {
  238.     //
  239.     // Private Debug stuff
  240.     //
  241. #if ANDREVA_DBG
  242.     g_dwTraceFlags = 0xFFFFFFFF;
  243. #endif
  244.     InitCommonControls();
  245.     CreateGlobals();
  246.     return TRUE;
  247. }
  248. ///////////////////////////////////////////////////////////////////////////////
  249. // SetStartPage checks the command line for start page by name.
  250. ///////////////////////////////////////////////////////////////////////////////
  251. void SetStartPage(PROPSHEETHEADER *ppsh, LPCTSTR pszCmdLine)
  252. {
  253.     if (pszCmdLine)
  254.     {
  255.         //
  256.         // Strip spaces
  257.         //
  258.         while (*pszCmdLine == TEXT(' '))
  259.         {
  260.             pszCmdLine++;
  261.         }
  262.         //
  263.         // Check for @ sign.
  264.         //
  265.         if (*pszCmdLine == TEXT('@'))
  266.         {
  267.             LPTSTR pszStartPage;
  268.             LPCTSTR pszBegin;
  269.             BOOL fInQuote = FALSE;
  270.             int cchLen;
  271.             pszCmdLine++;
  272.             //
  273.             // Skip past a quote
  274.             //
  275.             if (*pszCmdLine == TEXT('"'))
  276.             {
  277.                 pszCmdLine++;
  278.                 fInQuote = TRUE;
  279.             }
  280.             //
  281.             // Save the beginning of the name.
  282.             //
  283.             pszBegin = pszCmdLine;
  284.             //
  285.             // Find the end of the name.
  286.             //
  287.             while (*pszCmdLine &&
  288.                    (fInQuote || *pszCmdLine != TEXT(' ')) &&
  289.                    (!fInQuote || *pszCmdLine != TEXT('"')))
  290.             {
  291.                 pszCmdLine++;
  292.             }
  293.             cchLen = (int)(pszCmdLine - pszBegin);
  294.             //
  295.             // Store the name in the pStartPage field.
  296.             //
  297.             pszStartPage = (LPTSTR)LocalAlloc(LPTR, (cchLen+1) * SIZEOF(TCHAR));
  298.             if (pszStartPage)
  299.             {
  300.                 lstrcpyn(pszStartPage, pszBegin, cchLen+1);
  301.                 ppsh->dwFlags |= PSH_USEPSTARTPAGE;
  302.                 ppsh->pStartPage = pszStartPage;
  303.             }
  304.         }
  305.     }
  306. }
  307. ///////////////////////////////////////////////////////////////////////////////
  308. // _AddDisplayPropSheetPage  adds pages for outside callers...
  309. ///////////////////////////////////////////////////////////////////////////////
  310. BOOL CALLBACK
  311. _AddDisplayPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
  312. {
  313.     PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *)lParam;
  314.     if( hpage && ( ppsh->nPages < MAX_PAGES ) )
  315.     {
  316.         ppsh->phpage[ppsh->nPages++] = hpage;
  317.         return TRUE;
  318.     }
  319.     return FALSE;
  320. }
  321. static int
  322. GetClInt( const TCHAR *p )
  323. {
  324.     BOOL neg = FALSE;
  325.     int v = 0;
  326.     while( *p == TEXT(' ') )
  327.         p++;                        // skip spaces
  328.     if( *p == TEXT('-') )                 // is it negative?
  329.     {
  330.         neg = TRUE;                     // yes, remember that
  331.         p++;                            // skip '-' char
  332.     }
  333.     // parse the absolute portion
  334.     while( ( *p >= TEXT('0') ) && ( *p <= TEXT('9') ) )     // digits only
  335.         v = v * 10 + *p++ - TEXT('0');    // accumulate the value
  336.     return ( neg? -v : v );         // return the result
  337. }
  338. //  Checks the given restriction.  Returns TRUE (restricted) if the
  339. //  specified key/value exists and is non-zero, false otherwise
  340. BOOL CheckRestriction(HKEY hKey,LPCTSTR lpszValueName)
  341. {
  342.     DWORD dwData,dwSize=sizeof(dwData);
  343.     if ( (RegQueryValueEx(hKey,lpszValueName,NULL,NULL,
  344.         (BYTE *) &dwData,&dwSize) == ERROR_SUCCESS) &&
  345.         dwData)
  346.         return TRUE;
  347.     return FALSE;
  348. }
  349. ///////////////////////////////////////////////////////////////////////////////
  350. // CreateReplaceableHPSXA creates a new hpsxa that contains only the
  351. // interfaces with valid ReplacePage methods.
  352. // APPCOMPAT - EzDesk only implemented AddPages.  ReplacePage is NULL for them.
  353. ///////////////////////////////////////////////////////////////////////////////
  354. typedef struct {
  355.     UINT count, alloc;
  356.     IShellPropSheetExt *interfaces[0];
  357. } PSXA;
  358. HPSXA
  359. CreateReplaceableHPSXA(HPSXA hpsxa)
  360. {
  361.     PSXA *psxa = (PSXA *)hpsxa;
  362.     DWORD cb = SIZEOF(PSXA) + SIZEOF(IShellPropSheetExt *) * psxa->alloc;
  363.     PSXA *psxaRet = (PSXA *)LocalAlloc(LPTR, cb);
  364.     if (psxaRet)
  365.     {
  366.         UINT i;
  367.         psxaRet->count = 0;
  368.         psxaRet->alloc = psxa->alloc;
  369.         for (i=0; i<psxa->count; i++)
  370.         {
  371.             if (psxa->interfaces[i]->lpVtbl->ReplacePage)
  372.             {
  373.                 psxaRet->interfaces[psxaRet->count++] = psxa->interfaces[i];
  374.             }
  375.         }
  376.     }
  377.     return (HPSXA)psxaRet;
  378. }
  379. #define DestroyReplaceableHPSXA(hpsxa) LocalFree((HLOCAL)hpsxa)
  380. /*****************************************************************************
  381. *
  382. * DeskShowPropSheet( HWND hwndParent )
  383. *
  384. *****************************************************************************/
  385. typedef HRESULT (*LPFNCOINIT)(LPVOID);
  386. typedef HRESULT (*LPFNCOUNINIT)(void);
  387. int ComputeNumberOfDisplayDevices();
  388. void DeskShowPropSheet( HINSTANCE hInst, HWND hwndParent, LPCTSTR cmdline )
  389. {
  390. #ifndef WINNT  // Comments below
  391.     HINSTANCE hDesk16 = NULL;
  392.     FARPROC16 pDesk16 = NULL;
  393. #endif
  394.     HPROPSHEETPAGE hpsp, ahPages[MAX_PAGES];
  395.     HPSXA hpsxa = NULL;
  396.     PROPSHEETPAGE psp;
  397.     PROPSHEETHEADER psh;
  398.     HINSTANCE hinstOLE32 = NULL;
  399.     LPFNCOINIT lpfnCoInitialize = NULL;
  400.     LPFNCOUNINIT lpfnCoUninitialize = NULL;
  401.     HKEY hKey;
  402.     int i;
  403.     DWORD exitparam = 0UL;
  404.     //
  405.     // move win95 OEM registry handlers around
  406.     //
  407.     // On NT, we don't do this since we don't have PnP for NT 4.0, and we
  408.     // therefore have to software section associated to the driver.
  409.     // We do redefine the layout of the Controls Folder so that all extensions
  410.     // will only show up under the Advacned settings tab - but they will remain
  411.     // global until the extensions are rev'ed for NT 5.0
  412.     //
  413. #ifndef WINNT
  414.     FixupRegistryHandlers();
  415. #endif
  416.     //
  417.     // check if whole sheet is locked out
  418.     //
  419.     if ((RegOpenKey(HKEY_CURRENT_USER,
  420.                     REGSTR_PATH_POLICIES TEXT("\") REGSTR_KEY_SYSTEM,
  421.                     &hKey) == ERROR_SUCCESS)) {
  422.         BOOL fDisableCPL = CheckRestriction(hKey,REGSTR_VAL_DISPCPL_NODISPCPL);
  423.         if (fDisableCPL) {
  424.             TCHAR szMessage[255],szTitle[255];
  425.             RegCloseKey(hKey);
  426.             LoadString( hInst, IDS_DISPLAY_DISABLED, szMessage, ARRAYSIZE(szMessage) );
  427.             LoadString( hInst, IDS_DISPLAY_TITLE, szTitle, ARRAYSIZE(szTitle) );
  428.             MessageBox( hwndParent, szMessage, szTitle, MB_OK | MB_ICONINFORMATION );
  429.             return;
  430.         }
  431.     }
  432.     else
  433.     {
  434.         hKey = NULL;
  435.     }
  436.     //
  437.     // Create the property sheet
  438.     //
  439.     ZeroMemory( &psh, sizeof(psh) );
  440.     psh.dwSize = sizeof(PROPSHEETHEADER);
  441.     psh.dwFlags = PSH_PROPTITLE;
  442.     psh.hwndParent = hwndParent;
  443.     psh.hInstance = hInst;
  444.     psh.pszCaption = MAKEINTRESOURCE( IDS_DISPLAY_TITLE );
  445.     psh.nPages = 0;
  446.     psh.phpage = ahPages;
  447.     psh.nStartPage = ( ( cmdline && *cmdline )? GetClInt( cmdline ) : 0 );
  448.     ZeroMemory( &psp, sizeof(psp) );
  449.     psp.dwSize = sizeof(psp);
  450.     psp.dwFlags = PSP_DEFAULT;
  451.     psp.hInstance = hInst;
  452. #ifndef WINNT
  453.     // check for special command line casess
  454.     if (psh.nStartPage == -1)
  455.     {
  456.         hDesk16 = LoadLibrary16( "DeskCp16.Dll" );
  457.         pDesk16 = (FARPROC16)( hDesk16? GetProcAddress16( hDesk16, "CplApplet" ) : NULL );
  458.         // USER couldn't start the display and needs our help
  459.         // kick up the fallback settings page...
  460.         gbExecMode    = EXEC_INVALID_MODE;
  461.         gbInvalidMode = EXEC_INVALID_DISPLAY_MODE;
  462.         //
  463.         // call deskcp16.dll and let it try to diagnose the display
  464.         // problem, it will try to figure out what is wrong and
  465.         // either send the user to a HLP file, or add the Settings
  466.         // page.  if it adds a Settings page, we want to remove it
  467.         // and add ours
  468.         //
  469.         if (pDesk16 && CallCPLEntry16( hDesk16, pDesk16, NULL, CPL_INIT, 0, 0))
  470.         {
  471.             psh.nStartPage = 0;
  472.         
  473.             // Have our 16-bit dll add the fallback page
  474.             SHAddPages16( NULL, "DESKCP16.DLL,GetDisplayFallbackPage",
  475.                           _AddDisplayPropSheetPage, (LPARAM)&psh );
  476.             //
  477.             // if the 16bit code did not add a page, we should not show ours
  478.             //
  479.             if (psh.nPages == 0)
  480.             {
  481.                 return;
  482.             }
  483.             //
  484.             // nuke the pages that deskcp16 added
  485.             //
  486.             while (psh.nPages > 0)
  487.             {
  488.                 psh.nPages--;
  489.                 DestroyPropertySheetPage(psh.phpage[psh.nPages]);
  490.                 psh.phpage[psh.nPages] = NULL;
  491.             }
  492.         }
  493.     }
  494. #endif
  495.     // GetSystemMetics(SM_CMONITORS) returns only the enabled monitors. So, we need to 
  496.     // enumerate ourselves to determine if this is a multimonitor scenario. We have our own
  497.     // function to do this.
  498.     // Use the appropriate dlg template for multimonitor and single monitor configs.
  499.     // if(GetSystemMetrics(SM_CMONITORS) > 1)
  500.     if(ComputeNumberOfDisplayDevices() > 1)
  501.         aPageInfo[IPI_SETTINGS].id = DLG_MULTIMONITOR;
  502.     else
  503.         aPageInfo[IPI_SETTINGS].id = DLG_SINGLEMONITOR;
  504.     /*
  505.      * Build the property sheet.  If we are under setup, then just include
  506.      * the "settings" page, and no otheres
  507.      */
  508.     if (gbExecMode == EXEC_NORMAL)
  509.     {
  510.         //
  511.         // Load the OLE library and grab the two interesting entry points.
  512.         //
  513.         hinstOLE32 = LoadLibrary(TEXT("OLE32.DLL"));
  514.         if (hinstOLE32)
  515.         {
  516.             lpfnCoInitialize = (LPFNCOINIT)GetProcAddress(hinstOLE32, "CoInitialize");
  517.             lpfnCoUninitialize = (LPFNCOUNINIT)GetProcAddress(hinstOLE32, "CoUninitialize");
  518.             if (!lpfnCoInitialize || !lpfnCoUninitialize)
  519.             {
  520.                 lpfnCoInitialize = NULL;
  521.                 lpfnCoUninitialize = NULL;
  522.                 FreeLibrary(hinstOLE32);
  523.                 hinstOLE32 = NULL;
  524.             }
  525.         }
  526.         //
  527.         // Initialize COM
  528.         //
  529.         if (lpfnCoInitialize) {
  530.             lpfnCoInitialize(NULL);
  531.         }
  532.         if (!GetSystemMetrics(SM_CLEANBOOT))
  533.         {
  534. #ifdef WINNT
  535.             hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE,
  536.                                               REGSTR_PATH_CONTROLSFOLDER TEXT("\Desk"), 8);
  537. #else
  538.             hpsxa = SHCreatePropSheetExtArray(HKEY_LOCAL_MACHINE,
  539.                                               REGSTR_PATH_CONTROLSFOLDER TEXT("\Display"), 8);
  540. #endif
  541.         }
  542.         for( i = 0; i < C_PAGES_DESK; i++ )
  543.         {
  544.             BOOL    fHideThisPage = FALSE;
  545.             
  546.             if (hKey != NULL && CheckRestriction(hKey,aPageInfo[i].szRegChkName))
  547.             {
  548.                 //
  549.                 // This page is locked out by admin, don't put it up
  550.                 //
  551.                 fHideThisPage = TRUE;
  552.             }
  553.             psp.pszTemplate = MAKEINTRESOURCE(aPageInfo[i].id);
  554.             psp.pfnDlgProc = aPageInfo[i].pfnDlgProc;
  555.             psp.dwFlags = PSP_DEFAULT;
  556.             psp.lParam = 0L;
  557. #ifdef WINNT
  558.             //
  559.             // For Terminal Services, we need to hide the Background tab if a machine
  560.             // policy is set to not allow wallpaper changes for this session.
  561.             //
  562.             if (psp.pfnDlgProc == BackgroundDlgProc &&
  563.                   GetSystemMetrics(SM_REMOTESESSION) &&
  564.                   !fHideThisPage )
  565.             {
  566.                 TCHAR   szSessionName[WINSTATIONNAME_LENGTH * 2];
  567.                 TCHAR   szWallPaper[MAX_PATH*2];
  568.                 TCHAR   szBuf[MAX_PATH*2];
  569.                 TCHAR   szActualValue[MAX_PATH*2];
  570.                 DWORD   dwLen;
  571.                 DWORD   i;
  572.                 ZeroMemory((PVOID)szSessionName,sizeof(szSessionName));
  573.                 dwLen = GetEnvironmentVariable(TEXT("SESSIONNAME"),szSessionName,ARRAYSIZE(szSessionName));
  574.                 if (dwLen != 0)
  575.                 {
  576.                     //
  577.                     // Now that we have the session name, search for the # character.
  578.                     //
  579.                     for(i = 0; i < dwLen; i++) {
  580.                         if (szSessionName[i] == TEXT('#')) {
  581.                             szSessionName[i] = TEXT('');
  582.                             break;
  583.                         }
  584.                     }
  585.                     // Here is what we are looking for in NT5:
  586.                     //  HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server
  587.                     //      WinStationsRDP-TcpUserOverrideControl PanelDesktop
  588.                     //
  589.                     // The value is:
  590.                     //      Wallpaper
  591.                     //
  592.                     lstrcpy(szWallPaper,WALLPAPER);
  593.                     lstrcpy(szBuf, WINSTATION_REG_NAME );  
  594.                     lstrcat(szBuf, L"\" );
  595.                     lstrcat(szBuf, szSessionName );
  596.                     lstrcat(szBuf, L"\" );
  597.                     lstrcat(szBuf, WIN_USEROVERRIDE );
  598.                     lstrcat(szBuf, L"\" );
  599.                     lstrcat(szBuf, REGSTR_PATH_DESKTOP );   // Control Panel\Desktop
  600.                     //
  601.                     // See if we can get the wallpaper string.  This will fail if the key
  602.                     // doesn't exist.  This means the policy isn't set.
  603.                     //
  604.                     //                                 hKey, lpszSubkey, lpszValueName, lpszDefault, 
  605.                     if (GetStringFromReg(HKEY_LOCAL_MACHINE, szBuf,      szWallPaper,   TEXT(""),    
  606.                                             // lpszValue,     cchSizeofValueBuff)
  607.                                                szActualValue, ARRAYSIZE(szActualValue)))
  608.                     {
  609.                         fHideThisPage = TRUE;
  610.                     }
  611.                 }
  612.             }
  613. #endif
  614.             if (!fHideThisPage && (psp.pfnDlgProc == BackgroundDlgProc)) {
  615.                 // This page can be overridden by extensions
  616.                 if( hpsxa ) {
  617.                     UINT cutoff = psh.nPages;
  618.                     UINT added = 0;
  619.                     HPSXA hpsxaReplace = CreateReplaceableHPSXA(hpsxa);
  620.                     if (hpsxaReplace)
  621.                     {
  622.                         added = SHReplaceFromPropSheetExtArray( hpsxaReplace, CPLPAGE_DISPLAY_BACKGROUND,
  623.                             _AddDisplayPropSheetPage, (LPARAM)&psh );
  624.                         DestroyReplaceableHPSXA(hpsxaReplace);
  625.                     }
  626.                     if (added) {
  627.                         if (psh.nStartPage >= cutoff)
  628.                             psh.nStartPage += added-1;
  629.                         continue;
  630.                     }
  631.                 }
  632.             }
  633.             //
  634.             // add extensions from the registry
  635.             // CAUTION: Do not check for "fHideThisPage" here. We need to add the pages for 
  636.             // property sheet extensions even if the "Settings" page is hidden.
  637.             //
  638.             if (psp.pfnDlgProc == MultiMonitorDlgProc && hpsxa)
  639.             {
  640.                 UINT cutoff = psh.nPages;
  641.                 UINT added = SHAddFromPropSheetExtArray( hpsxa,
  642.                     _AddDisplayPropSheetPage, (LPARAM)&psh );
  643.                 if (psh.nStartPage >= cutoff)
  644.                     psh.nStartPage += added;
  645.             }
  646.             if (!fHideThisPage && (hpsp = CreatePropertySheetPage(&psp)))
  647.             {
  648.                 psh.phpage[psh.nPages++] = hpsp;
  649.             }
  650.         }
  651.         //
  652.         // add a fake settings page to fool OEM extensions
  653.         //
  654.         // !!! this page must be last !!!
  655.         //
  656.         if (hpsxa)
  657.         {
  658.             AddFakeSettingsPage(&psh);
  659.         }
  660.     }
  661.     else
  662.     {
  663.         //
  664.         // For the SETUP case, only the display page should show up.
  665.         //
  666.         psp.pszTemplate = MAKEINTRESOURCE(aPageInfo[IPI_SETTINGS].id);
  667.         psp.pfnDlgProc = aPageInfo[IPI_SETTINGS].pfnDlgProc;
  668.         if (hpsp = CreatePropertySheetPage(&psp)) {
  669.             psh.phpage[psh.nPages++] = hpsp;
  670.         }
  671.     }
  672.     
  673.     if (psh.nStartPage >= psh.nPages)
  674.         psh.nStartPage = 0;
  675.     if (hKey != NULL)
  676.         RegCloseKey(hKey);
  677.     if (psh.nPages)
  678.     {
  679.         SetStartPage(&psh, cmdline);
  680.         if (PropertySheet(&psh) == ID_PSRESTARTWINDOWS)
  681.         {
  682.             exitparam = EWX_REBOOT;
  683.         }
  684.     }
  685.     // free any loaded extensions
  686.     if (hpsxa)
  687.     {
  688.         SHDestroyPropSheetExtArray(hpsxa);
  689.     }
  690. #ifndef WINNT
  691.     if (pDesk16)
  692.         CallCPLEntry16( hDesk16, pDesk16, NULL, CPL_EXIT, 0, 0 );
  693.    
  694.     if( hDesk16 )
  695.         FreeLibrary16( hDesk16 );
  696. #endif
  697.     //
  698.     // We are done with propsheetextarray code, uninitialize com
  699.     // and unload OLE32 dll.
  700.     //
  701.     if (lpfnCoUninitialize)
  702.     {
  703.         lpfnCoUninitialize();
  704.     }
  705.     if (hinstOLE32)
  706.     {
  707.         lpfnCoInitialize = NULL;
  708.         lpfnCoUninitialize = NULL;
  709.         FreeLibrary(hinstOLE32);
  710.         hinstOLE32 = NULL;
  711.     }
  712.     
  713.     if (exitparam == EWX_REBOOT)
  714.         RestartDialog( hwndParent, NULL, exitparam );
  715.     return;
  716. }
  717. DWORD gdwCoverStyle = WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
  718. #if 0 // This code creates another thread for the cover window, which we don't really need
  719.       // and is causing a problem. I am not sure if this is needed for NT, so leave it here....
  720. ///////////////////////////////////////////////////////////////////////////////
  721. //
  722. // CreateCoverWindow
  723. //
  724. // creates a window which obscures the display
  725. //  flags:
  726. //      0 means erase to black
  727. //      COVER_NOPAINT means "freeze" the display
  728. //
  729. // just post it a WM_CLOSE when you're done with it
  730. //
  731. ///////////////////////////////////////////////////////////////////////////////
  732. typedef struct {
  733.     DWORD   flags;
  734.     HWND    hwnd;
  735.     HANDLE  heRetvalSet;
  736. } CVRWNDPARM, * PCVRWNDPARM;
  737. DWORD WINAPI CreateCoverWindowThread( LPVOID pv )
  738. {
  739.     PCVRWNDPARM pcwp = (PCVRWNDPARM)pv;
  740.     MSG msg;
  741.     pcwp->hwnd = CreateWindowEx( gdwCoverStyle,
  742.         sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | pcwp->flags, 0, 0,
  743.         GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ),
  744.         NULL, NULL, hInstance, NULL );
  745.     if( pcwp->hwnd )
  746.     {
  747.         SetForegroundWindow( pcwp->hwnd );
  748.         UpdateWindow( pcwp->hwnd );
  749.     }
  750.     // return wnd;
  751.     SetEvent(pcwp->heRetvalSet);
  752.     /* Acquire and dispatch messages until a WM_QUIT message is received. */
  753.     while (GetMessage(&msg, NULL, 0L, 0L)) {
  754.         TranslateMessage(&msg);
  755.         DispatchMessage(&msg);
  756.     }
  757.     ExitThread(0);
  758.     return 0;
  759. }
  760. void DestroyCoverWindow(HWND hwndCover)
  761. {
  762.     if (hwndCover)
  763.         PostMessage(hwndCover, WM_CLOSE, 0, 0L);
  764. }
  765. HWND FAR PASCAL
  766. CreateCoverWindow( DWORD flags )
  767. {
  768.     CVRWNDPARM cwp;
  769.     HANDLE hThread;
  770.     DWORD  idTh;
  771.     DWORD dwWaitResult  = 0;
  772.     // Init params
  773.     cwp.flags = flags;
  774.     cwp.hwnd = NULL;
  775.     cwp.heRetvalSet = CreateEvent(NULL, TRUE, FALSE, NULL);
  776.     if (cwp.heRetvalSet == NULL)
  777.         return NULL;
  778.     // CreateThread
  779.     hThread = CreateThread(NULL, 0, CreateCoverWindowThread, &cwp, 0, &idTh);
  780.     CloseHandle(hThread);
  781.     // Wait for Thread to return the handle to us
  782.     do
  783.     {
  784.         dwWaitResult = MsgWaitForMultipleObjects(1,
  785.                                                  &cwp.heRetvalSet,
  786.                                                  FALSE,
  787.                                                  INFINITE,
  788.                                                  QS_ALLINPUT);
  789.         switch(dwWaitResult)
  790.         {
  791.             case WAIT_OBJECT_0 + 1:
  792.             {
  793.                 MSG msg ;
  794.                 //
  795.                 // Allow blocked thread to respond to sent messages.
  796.                 //
  797.                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  798.                 {
  799.                     if ( WM_QUIT != msg.message )
  800.                     {
  801.                         TranslateMessage(&msg);
  802.                         DispatchMessage(&msg);
  803.                     }
  804.                     else
  805.                     {
  806.                         //
  807.                         // Received WM_QUIT.
  808.                         // Don't wait for event.
  809.                         //
  810.                         dwWaitResult = WAIT_FAILED;
  811.                     }
  812.                 }
  813.                 break;
  814.             }
  815.             default:
  816.                 break;
  817.         }
  818.     }
  819.     while((WAIT_OBJECT_0 + 1) == dwWaitResult);
  820.     CloseHandle(cwp.heRetvalSet);
  821.     return cwp.hwnd;
  822. }
  823. #endif
  824. void DestroyCoverWindow(HWND hwndCover)
  825. {
  826.     DestroyWindow(hwndCover);
  827. }
  828. HWND FAR PASCAL CreateCoverWindow( DWORD flags )
  829. {
  830.     HWND hwndCover = CreateWindowEx( gdwCoverStyle,
  831.                                      sc_szCoverClass, g_szNULL, WS_POPUP | WS_VISIBLE | flags, 
  832.                                      GetSystemMetrics( SM_XVIRTUALSCREEN ), 
  833.                                      GetSystemMetrics( SM_YVIRTUALSCREEN ), 
  834.                                      GetSystemMetrics( SM_CXVIRTUALSCREEN ), 
  835.                                      GetSystemMetrics( SM_CYVIRTUALSCREEN ),
  836.                                      NULL, NULL, hInstance, NULL );
  837.     if( hwndCover )
  838.     {
  839.         SetForegroundWindow( hwndCover );
  840.         if (flags & COVER_NOPAINT)
  841.             SetCursor(LoadCursor(NULL, IDC_WAIT));
  842.         UpdateWindow( hwndCover);
  843.     }
  844.     return hwndCover;
  845. }
  846. ///////////////////////////////////////////////////////////////////////////////
  847. // CoverWndProc (see CreateCoverWindow)
  848. ///////////////////////////////////////////////////////////////////////////////
  849. #define WM_PRIV_KILL_LATER  (WM_APP + 100)  //Private message to kill ourselves later.
  850. LRESULT CALLBACK
  851. CoverWindowProc( HWND window, UINT message, WPARAM wparam, LPARAM lparam )
  852. {
  853.     switch( message )
  854.     {
  855.         case WM_CREATE:
  856.             SetTimer( window, ID_CVRWND_TIMER, CMSEC_COVER_WINDOW_TIMEOUT, NULL );
  857.             break;
  858.         case WM_TIMER:
  859.             // Times up... Shut ourself down
  860.             if (wparam == ID_CVRWND_TIMER)
  861.                 DestroyWindow(window);
  862.             break;
  863.         case WM_ERASEBKGND:
  864.             // NOTE: assumes our class brush is the NULL_BRUSH stock object
  865.             if( !( GetWindowLong( window, GWL_STYLE ) & COVER_NOPAINT ) )
  866.             {
  867.                 HDC dc = (HDC)wparam;
  868.                 RECT rc;
  869.                 if( GetClipBox( dc, (LPRECT)&rc ) != NULLREGION )
  870.                 {
  871.                     FillRect( dc, (LPRECT)&rc, GetStockObject( BLACK_BRUSH ) );
  872.                     // HACK: make sure fillrect is done before we return
  873.                     // this is to better hide flicker during dynares-crap
  874.                     GetPixel( dc, rc.left + 1, rc.top + 1 );
  875.                 }
  876.             }
  877.             break;
  878.         // We post a private message to ourselves because:
  879.         // When WM_CLOSE is processed by this window, it calls DestroyWindow() which results in
  880.         // WM_ACTIVATE (WA_INACTIVE) message to be sent to this window. If this code calls
  881.         // DestroyWindow again, it causes a loop. So, instead of calling DestroyWindow immediately,
  882.         // we post ourselves a message and destroy us letter.
  883.         case WM_ACTIVATE:
  884.             if( GET_WM_ACTIVATE_STATE( wparam, lparam ) == WA_INACTIVE )
  885.             {
  886.                 PostMessage( window, WM_PRIV_KILL_LATER, 0L, 0L );
  887.                 return 1L;
  888.             }
  889.             break;
  890.         case WM_PRIV_KILL_LATER:
  891.             DestroyWindow(window);
  892.             break;
  893.         case WM_DESTROY:
  894.             KillTimer(window, ID_CVRWND_TIMER);
  895.             break;
  896.     }
  897.     return DefWindowProc( window, message, wparam, lparam );
  898. }
  899. BOOL _FindCoverWindowCallback(HWND hwnd, LPARAM lParam)
  900. {
  901.     TCHAR szClass[MAX_PATH];
  902.     HWND *phwnd = (HWND*)lParam;
  903.     if( !GetClassName(hwnd, szClass, ARRAYSIZE(szClass)) )
  904.         return TRUE;
  905.     if( lstrcmp(szClass, sc_szCoverClass) == 0 )
  906.     {
  907.         if( phwnd )
  908.             *phwnd = hwnd;
  909.         return FALSE;
  910.     }
  911.     return TRUE;
  912. }
  913. LONG APIENTRY CPlApplet(
  914.     HWND  hwnd,
  915.     WORD  message,
  916.     DWORD wParam,
  917.     LONG  lParam)
  918. {
  919.     LPCPLINFO lpCPlInfo;
  920.     LPNEWCPLINFO lpNCPlInfo;
  921.     HWND hwndCover;
  922.     switch (message)
  923.     {
  924.       case CPL_INIT:          // Is any one there ?
  925.         /*
  926.          * Init the common controls
  927.          */
  928.         if (!DeskInitCpl())
  929.             return 0;
  930.         /*
  931.          * Load ONE string for emergencies.
  932.          */
  933.         LoadString (hInstance, IDS_DISPLAY_TITLE, gszDeskCaption, ARRAYSIZE(gszDeskCaption));
  934.         return !0;
  935.       case CPL_GETCOUNT:        // How many applets do you support ?
  936.         return 1;
  937.       case CPL_INQUIRE:         // Fill CplInfo structure
  938.         lpCPlInfo = (LPCPLINFO)lParam;
  939.         lpCPlInfo->idIcon = IDI_DISPLAY;
  940.         lpCPlInfo->idName = IDS_NAME;
  941.         lpCPlInfo->idInfo = IDS_INFO;
  942.         lpCPlInfo->lData  = 0;
  943.         break;
  944.     case CPL_NEWINQUIRE:
  945.         lpNCPlInfo = (LPNEWCPLINFO)lParam;
  946.         lpNCPlInfo->hIcon = LoadIcon(hInstance, (LPTSTR) MAKEINTRESOURCE(IDI_DISPLAY));
  947.         LoadString(hInstance, IDS_NAME, lpNCPlInfo->szName, ARRAYSIZE(lpNCPlInfo->szName));
  948.         if (!LoadString(hInstance, IDS_INFO, lpNCPlInfo->szInfo, ARRAYSIZE(lpNCPlInfo->szInfo)))
  949.             lpNCPlInfo->szInfo[0] = (TCHAR) 0;
  950.         lpNCPlInfo->dwSize = sizeof( NEWCPLINFO );
  951.         lpNCPlInfo->lData  = 0;
  952. #if 0
  953.         lpNCPlInfo->dwHelpContext = IDH_CHILD_DISPLAY;
  954.         lstrcpy(lpNCPlInfo->szHelpFile, xszControlHlp);
  955. #else
  956.         lpNCPlInfo->dwHelpContext = 0;
  957.         lstrcpy(lpNCPlInfo->szHelpFile, TEXT(""));
  958. #endif
  959.         return TRUE;
  960.       case CPL_DBLCLK:          // You have been chosen to run
  961.         /*
  962.          * One of your applets has been double-clicked.
  963.          *      wParam is an index from 0 to (NUM_APPLETS-1)
  964.          *      lParam is the lData value associated with the applet
  965.          */
  966.         lParam = 0L;
  967.         // fall through...
  968.       case CPL_STARTWPARMS:
  969.         DeskShowPropSheet( hInstance, hwnd, (LPTSTR)lParam );
  970.         // ensure that any cover windows we've created have been destroyed
  971.         do
  972.         {
  973.             hwndCover = 0;
  974.             EnumWindows( _FindCoverWindowCallback, (LPARAM)&hwndCover );
  975.             if( hwndCover )
  976.             {
  977.                 DestroyWindow( hwndCover );
  978.             }
  979.         }
  980.         while( hwndCover );
  981.         return TRUE;            // Tell RunDLL.exe that I succeeded
  982.       case CPL_EXIT:            // You must really die
  983.       case CPL_STOP:            // You must die
  984.         break;
  985.       case CPL_SELECT:          // You have been selected
  986.         /*
  987.          * Sent once for each applet prior to the CPL_EXIT msg.
  988.          *      wParam is an index from 0 to (NUM_APPLETS-1)
  989.          *      lParam is the lData value associated with the applet
  990.          */
  991.         break;
  992.       //
  993.       //  Private message sent when this applet is running under "Setup"
  994.       //
  995.       case CPL_SETUP:
  996.         gbExecMode = EXEC_SETUP;
  997.         break;
  998.       //
  999.       // Private message used by userenv.dll to refresh the display colors
  1000.       //
  1001.       case CPL_POLICYREFRESH:
  1002.         RefreshColors ();
  1003.         break;
  1004.         
  1005.     }
  1006.     return 0L;
  1007. }