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

Windows Kernel

Development Platform:

Visual C++

  1. /*  SSDLG.C
  2. **
  3. **  Copyright (C) Microsoft, 1999, All Rights Reserved.
  4. **
  5. **  History:
  6. **      18 Feb 94   (Tracy Sharpe) Added power management functionality.
  7. **                  Commented out several pieces of code that weren't being
  8. **                  used.
  9. */
  10. #include <windows.h>
  11. #include <commctrl.h>
  12. #include <scrnsave.h>
  13. #include "desk.h"
  14. #include "deskid.h"
  15. #include <shellapi.h>
  16. #include "exe.h"
  17. #include "deskid.h"
  18. #include <regstr.h>
  19. #define         SFSE_SYSTEM     0
  20. #define         SFSE_PRG        1
  21. #define         SFSE_WINDOWS    2
  22. #define         SFSE_FILE       3
  23. /* Local function prototypes... */
  24. void  NEAR PASCAL SearchForScrEntries     ( UINT, LPCTSTR );
  25. BOOL  NEAR PASCAL FreeScrEntries          ( void );
  26. int   NEAR PASCAL lstrncmp                ( LPTSTR, LPTSTR, int );
  27. LPTSTR NEAR PASCAL FileName                ( LPTSTR szPath);
  28. LPTSTR NEAR PASCAL StripPathName           ( LPTSTR szPath);
  29. LPTSTR NEAR PASCAL NiceName                ( LPTSTR szPath);
  30. void  NEAR PASCAL AddBackslash(LPTSTR pszPath);
  31. void  NEAR PASCAL AppendPath(LPTSTR pszPath, LPTSTR pszSpec);
  32. PTSTR  NEAR PASCAL PerformCheck(LPTSTR, BOOL);
  33. PTSTR  NEAR PASCAL AllocStr(LPTSTR szCopy);
  34. void  NEAR PASCAL SaveIni(HWND hDlg);
  35. void  NEAR PASCAL DoScreenSaver(HWND hDlg, BOOL b);
  36. void NEAR PASCAL ScreenSaver_AdjustTimeouts(HWND hWnd,int BaseControlID);
  37. void NEAR PASCAL ScreenSaver_EnableDisableDelays(HWND hWnd,int BaseControlID);
  38. void NEAR PASCAL EnableDisablePowerDelays(HWND hDlg);
  39. void NEAR PASCAL EnableDisableSetPasswordBtn(HWND hDlg);
  40. TCHAR   szMethodName[]       = TEXT("SCRNSAVE.EXE");     // Method entry
  41. TCHAR   szBuffer[BUFFER_SIZE];                     // Shared buffer
  42. TCHAR   szSaverName[MAX_PATH];                    // Screen Saver EXE
  43. HICON  hDefaultIcon;
  44. HICON  hIdleWildIcon;
  45. BOOL    bWasConfig=0;   // We were configing the screen saver
  46. HWND    g_hwndTestButton;
  47. HWND    g_hwndLastFocus;
  48. BOOL    g_fPasswordWasPreviouslyEnabled = FALSE;
  49. // Local global variables
  50. HICON  hIcons[MAX_METHODS];
  51. UINT   wNumMethods;
  52. PTSTR   aszMethods[MAX_METHODS];
  53. PTSTR   aszFiles[MAX_METHODS];
  54. static const TCHAR c_szDemoParentClass[] = TEXT("SSDemoParent");
  55. //  static TCHAR szFileNameCopy[MAX_PATH];
  56. static int  g_iMethod;
  57. static BOOL g_fPreviewActive;
  58. static BOOL g_fAdapPwrMgnt = FALSE;
  59. /*
  60.  * Registry value for the "Password Protected" check box
  61.  *
  62.  * These are different for NT and Win95 to keep screen
  63.  * savers built exclusivly for Win95 from trying to
  64.  * handle password checks.  (NT does all password checking
  65.  * in the built in security system to maintain C2
  66.  * level security)
  67.  */
  68. #ifdef WINNT
  69. #   define SZ_USE_PASSWORD     TEXT("ScreenSaverIsSecure")
  70. #   define PWRD_REG_TYPE       REG_SZ
  71. #   define CCH_USE_PWRD_VALUE  2
  72. #   define CB_USE_PWRD_VALUE   (CCH_USE_PWRD_VALUE * SIZEOF(TCHAR))
  73. TCHAR gpwdRegYes[CCH_USE_PWRD_VALUE] = TEXT("1");
  74. TCHAR gpwdRegNo[CCH_USE_PWRD_VALUE]  = TEXT("0");
  75. #define PasswdRegData(f)    ((f) ? (PBYTE)gpwdRegYes : (PBYTE)gpwdRegNo)
  76. #else
  77. #   define SZ_USE_PASSWORD     REGSTR_VALUE_USESCRPASSWORD
  78. #   define PWRD_REG_TYPE       REG_DWORD
  79. #   define CB_USE_PWRD_VALUE   SIZEOF(DWORD)
  80. DWORD gpwdRegYes = 1;
  81. DWORD gpwdRegNo  = 0;
  82. #define PasswdRegData(f)    ((f) ? (PBYTE)&gpwdRegYes : (PBYTE)&gpwdRegNo)
  83. #endif
  84. UDACCEL udAccel[] = {{0,1},{2,5},{4,30},{8,60}};
  85. #include "help.h"
  86. const DWORD FAR aSaverHelpIds[] = {
  87.         IDC_NO_HELP_1,          IDH_COMM_GROUPBOX,
  88.         IDC_CHOICES,            IDH_DSKTPSCRSAVER_LISTBX,
  89.         IDC_SSDELAYLABEL,       IDH_DSKTPSCRSAVER_WAIT,
  90.         IDC_SSDELAYSCALE,       IDH_DSKTPSCRSAVER_WAIT,
  91.         IDC_SCREENSAVEDELAY,    IDH_DSKTPSCRSAVER_WAIT,
  92.         IDC_SCREENSAVEARROW,    IDH_DSKTPSCRSAVER_WAIT,
  93.         IDC_TEST,               IDH_DSKTPSCRSAVER_TEST,
  94.         IDC_SETTING,            IDH_DSKTPSCRSAVER_SETTINGS,
  95.         IDC_BIGICON,            IDH_DSKTPSCRSAVER_MONITOR,
  96.         IDC_ENERGY_TEXT,        IDH_COMM_GROUPBOX,
  97.         IDC_ENERGY_TEXT2,       IDH_SCRSAVER_LOWPOWSTANDBY,
  98.         IDC_ENERGY_TEXT3,       IDH_SCRSAVER_SHUTOFFPOW,
  99.         IDC_LOWPOWERSWITCH,     IDH_SCRSAVER_LOWPOWSTANDBY,
  100.         IDC_LOWPOWERDELAY,      IDH_SCRSAVER_LOWPOWSTANDBY,
  101.         IDC_LOWPOWERARROW,      IDH_SCRSAVER_LOWPOWSTANDBY,
  102.         IDC_POWEROFFSWITCH,     IDH_SCRSAVER_SHUTOFFPOW,
  103.         IDC_POWEROFFDELAY,      IDH_SCRSAVER_SHUTOFFPOW,
  104.         IDC_POWEROFFARROW,      IDH_SCRSAVER_SHUTOFFPOW,
  105.         IDC_ENERGYSTAR_BMP,     IDH_SCRSAVER_GRAPHIC,
  106.         IDC_USEPASSWORD,        IDH_COMM_PASSWDCHKBOX,
  107.         IDC_SETPASSWORD,        IDH_COMM_PASSWDBUTT,
  108.         0, 0
  109. };
  110. //
  111. //  To simplify some things, the base control ID of a time control is associated
  112. //  with its corresponding SystemParametersInfo action codes.
  113. //
  114. typedef struct {
  115.     int taBaseControlID;
  116.     UINT taGetTimeoutAction;
  117.     UINT taSetTimeoutAction;
  118.     UINT taGetActiveAction;
  119.     UINT taSetActiveAction;
  120. }   TIMEOUT_ASSOCIATION;
  121. //
  122. //  Except for the case of the "screen save" delay, each time grouping has three
  123. //  controls-- a switch to determine whether that time should be used or not and
  124. //  an edit box and an updown control to change the delay time.  ("Screen save"
  125. //  is turned off my choosing (None) from the screen saver list)  These three
  126. //  controls must be organized as follows:
  127. //
  128. #define BCI_DELAY               0
  129. #define BCI_ARROW               1
  130. #define BCI_SWITCH              2
  131. //
  132. //  Associations between base control IDs and SystemParametersInfo action codes.
  133. //  The TA_* #defines are used as symbolic indexes into this array.  Note that
  134. //  TA_SCREENSAVE is a special case-- it does NOT have a BCI_SWITCH.
  135. //
  136. #define TA_SCREENSAVE           0
  137. #define TA_LOWPOWER             1
  138. #define TA_POWEROFF             2
  139. TIMEOUT_ASSOCIATION g_TimeoutAssociation[] = {
  140.     IDC_SCREENSAVEDELAY, SPI_GETSCREENSAVETIMEOUT, SPI_SETSCREENSAVETIMEOUT,
  141.         SPI_GETSCREENSAVEACTIVE, SPI_SETSCREENSAVEACTIVE,
  142.     IDC_LOWPOWERDELAY, SPI_GETLOWPOWERTIMEOUT, SPI_SETLOWPOWERTIMEOUT,
  143.         SPI_GETLOWPOWERACTIVE, SPI_SETLOWPOWERACTIVE,
  144.     IDC_POWEROFFDELAY, SPI_GETPOWEROFFTIMEOUT, SPI_SETPOWEROFFTIMEOUT,
  145.         SPI_GETPOWEROFFACTIVE, SPI_SETPOWEROFFACTIVE
  146. };
  147. int g_Timeout[] = {
  148.     0,
  149.     0,
  150.     0,
  151. };
  152. HBITMAP g_hbmDemo = NULL;
  153. HBITMAP g_hbmEnergyStar = NULL;
  154. BOOL g_bInitSS = TRUE;          // assume we are in initialization process
  155. BOOL g_bChangedSS = FALSE;      // changes have been made
  156. /*
  157.  * Win95 and NT store different values in different places of the registry to
  158.  * determine if the screen saver is secure or not.
  159.  *
  160.  * We can't really consolidate the two because the screen savers do different
  161.  * actions based on which key is set.  Win95 screen savers do their own
  162.  * password checking, but NT must let the secure desktop winlogon code do it.
  163.  *
  164.  * Therefore to keep Win95 screen savers from requesting the password twice on
  165.  * NT, we use  REGSTR_VALUE_USESCRPASSWORD == (REG_DWORD)1 on Win95 to indicate
  166.  * that a screen saver should check for the password, and
  167.  * "ScreenSaverIsSecure" == (REG_SZ)"1" on NT to indicate that WinLogon should
  168.  * check for a password.
  169.  *
  170.  * This function will deal with the differences.
  171.  */
  172. static BOOL IsPasswdSecure(HKEY hKey, LPTSTR szUsePW ) {
  173.     union {
  174.         DWORD dw;
  175.         TCHAR asz[4];
  176.     } uData;
  177.     DWORD dwSize, dwType;
  178.     BOOL fSecure = FALSE;
  179.     dwSize = SIZEOF(uData);
  180.     RegQueryValueEx(hKey,SZ_USE_PASSWORD,NULL, &dwType, (BYTE *)&uData, &dwSize);
  181.     switch( dwType ) {
  182.     case REG_DWORD:
  183.         fSecure = (uData.dw == 1);
  184.         break;
  185.     case REG_SZ:
  186.         fSecure = (uData.asz[0] == TEXT('1'));
  187.         break;
  188.     }
  189.     return fSecure;
  190. }
  191. static void NEAR
  192. EnableDlgChild( HWND dlg, HWND kid, BOOL val )
  193. {
  194.     if( !val && ( kid == GetFocus() ) )
  195.     {
  196.         // give prev tabstop focus
  197.         SendMessage( dlg, WM_NEXTDLGCTL, 1, 0L );
  198.     }
  199.     EnableWindow( kid, val );
  200. }
  201. static void NEAR
  202. EnableDlgItem( HWND dlg, int idkid, BOOL val )
  203. {
  204.     EnableDlgChild( dlg, GetDlgItem( dlg, idkid ), val );
  205. }
  206. HWND NEAR PASCAL GetSSDemoParent( HWND page )
  207. {
  208.     static HWND parent = NULL;
  209.     if( !parent || !IsWindow( parent ) )
  210.     {
  211.         parent = CreateWindowEx( 0, c_szDemoParentClass,
  212.             g_szNULL, WS_CHILD | WS_CLIPCHILDREN, 0, 0, 0, 0,
  213.             GetDlgItem( page, IDC_BIGICON ), NULL, hInstance, NULL );
  214.     }
  215.     return parent;
  216. }
  217. void NEAR PASCAL ForwardSSDemoMsg(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  218. {
  219.     HWND hwndChild;
  220.     hwnd = GetSSDemoParent(hwnd);
  221.     for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL;
  222.         hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
  223.     {
  224.         SendMessage(hwndChild, uMessage, wParam, lParam);
  225.     }
  226. }
  227. void NEAR PASCAL ParseSaverName( LPTSTR lpszName )
  228. {
  229.     if( *lpszName == TEXT('"') )
  230.     {
  231.         LPTSTR lpcSrc = lpszName + 1;
  232.         while( *lpcSrc && *lpcSrc != TEXT('"') )
  233.         {
  234.             *lpszName++ = *lpcSrc++;
  235.         }
  236.         *lpszName = 0;  // clear second quote
  237.     }
  238. }
  239. // YUCK:
  240. // since our screen saver preview is in a different process,
  241. //   it is possible that we paint in the wrong order.
  242. // this ugly hack makes sure the demo always paints AFTER the dialog
  243. WNDPROC g_lpOldStaticProc = NULL;
  244. LRESULT  StaticSubclassProc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
  245. {
  246.     LRESULT result =
  247.         CallWindowProc(g_lpOldStaticProc, wnd, msg, wp, lp);
  248.     if (msg == WM_PAINT)
  249.     {
  250.         HWND demos = GetSSDemoParent(GetParent(wnd));
  251.         if (demos)
  252.         {
  253.             RedrawWindow(demos, NULL, NULL,
  254.                 RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  255.         }
  256.     }
  257.     return result;
  258. }
  259. BOOL NEAR PASCAL InitSSDialog(HWND hDlg)
  260. {
  261.     WNDCLASS wc;
  262.     PTSTR  pszMethod;
  263.     UINT  wTemp,wLoop;
  264.     BOOL  fContinue;
  265.     int   Timeout;
  266.     int   Active;
  267.     UINT  Counter;
  268.     int   ControlID;
  269.     int   wMethod;
  270.     int   ScreenSaveActive;
  271.     DWORD dwData=0,dwSize = sizeof(dwData);
  272.     HKEY  hKey;
  273.     HWND  hwnd;
  274.     if( !GetClassInfo( hInstance, c_szDemoParentClass, &wc ) )
  275.     {
  276.         // if two pages put one up, share one dc
  277.         wc.style = 0;
  278.         wc.lpfnWndProc = DefWindowProc;
  279.         wc.cbClsExtra = wc.cbWndExtra = 0;
  280.         wc.hInstance = hInstance;
  281.         wc.hIcon = (HICON)( wc.hCursor = NULL );
  282.         wc.hbrBackground = GetStockObject( BLACK_BRUSH );
  283.         wc.lpszMenuName = NULL;
  284.         wc.lpszClassName = c_szDemoParentClass;
  285.         if( !RegisterClass( &wc ) )
  286.             return FALSE;
  287.     }
  288.     // Fetch the timeout value from the win.ini and adjust between 1:00-60:00
  289.     for (Counter = 0; Counter < (sizeof(g_TimeoutAssociation) /
  290.              sizeof(TIMEOUT_ASSOCIATION)); Counter++) {
  291.         // Fetch the timeout value from the win.ini and adjust between 1:00-60:00
  292.         SystemParametersInfo(g_TimeoutAssociation[Counter].taGetTimeoutAction, 0,
  293.             &Timeout, 0);
  294.         /*  The Win 3.1 guys decided that 0 is a valid ScreenSaveTimeOut value.
  295.          *  This causes our screen savers not to kick in (who cares?).  In any
  296.          *  case, I changed this to allow 0 to go through.  In this way, the
  297.          *  user immediately sees that the value entered is not valid to fire
  298.          *  off the screen saver--the OK button is disabled.  I don't know if
  299.          *  I fully agree with this solution--it is just the minimal amount of
  300.          *  code.  The optimal solution would be to ask the 3.1 guys why 0 is
  301.          *  valid?  -cjp
  302.          */
  303.         Timeout = min(max(Timeout, 1), MAX_MINUTES * 60);
  304.         //
  305.         //  Convert Timeout to minutes, rounding up.
  306.         //
  307.         Timeout = (Timeout + 59) / 60;
  308.         g_Timeout[Counter] = Timeout;
  309.         //
  310.         //  The base control id specifies the edit control id.
  311.         //
  312.         ControlID = g_TimeoutAssociation[Counter].taBaseControlID;
  313.         /* Set the maximum length of all of the fields... */
  314.         SendDlgItemMessage(hDlg, ControlID, EM_LIMITTEXT, 2, 0);
  315.         SystemParametersInfo(g_TimeoutAssociation[Counter].taGetActiveAction,
  316.             0, &Active, SPIF_UPDATEINIFILE);
  317.         if (Counter != TA_SCREENSAVE) {
  318.             CheckDlgButton(hDlg, ControlID + BCI_SWITCH, Active);
  319.         }
  320.         else {
  321.             ScreenSaveActive = Active;
  322.         }
  323.         SetDlgItemInt(hDlg, ControlID, Timeout, FALSE);
  324.         //
  325.         //  The associated up/down control id must be one after the edit control
  326.         //  id.
  327.         //
  328.         ControlID++;
  329.         SendDlgItemMessage(hDlg, ControlID, UDM_SETRANGE, 0,
  330.             MAKELPARAM(MAX_MINUTES, MIN_MINUTES));
  331.         SendDlgItemMessage(hDlg, ControlID, UDM_SETACCEL, 4,
  332.             (LPARAM)(LPUDACCEL)udAccel);
  333.     }
  334.     // Find the name of the exe used as a screen saver. "" means that the
  335.     // default screen saver will be used
  336.     GetPrivateProfileString(g_szBoot, szMethodName, g_szNULL, szSaverName,
  337.         ARRAYSIZE(szSaverName), g_szSystemIni);
  338.     ParseSaverName( szSaverName );  // remove quotes and params
  339.     /* Copy all of the variables into their copies... */
  340.     //  lstrcpy(szFileNameCopy, szSaverName);
  341.     /* Load in the default icon... */
  342.     hDefaultIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDS_ICON));
  343.     /* Find the methods to save the screen.  If the method that was
  344.         selected is not found, the program will assume that the
  345.         first method in the list will be the one that is elected... */
  346.     wNumMethods = 0;
  347.     wMethod = -1;
  348.     SearchForScrEntries(SFSE_PRG,NULL);
  349.     SearchForScrEntries(SFSE_SYSTEM,NULL);
  350.     SearchForScrEntries(SFSE_WINDOWS,NULL);
  351.     SearchForScrEntries(SFSE_FILE,szSaverName);
  352.     /* Set up the combo box for the different fields... */
  353.     SendDlgItemMessage(hDlg, IDC_CHOICES, CB_ADDSTRING, 0, (LONG)g_szNone);
  354.     for (wTemp = 0; wTemp < wNumMethods; wTemp++)
  355.     {
  356.         /* Lock down the information and pass it to the combo box... */
  357.         pszMethod = aszMethods[wTemp];
  358.         wLoop = SendDlgItemMessage(hDlg,IDC_CHOICES,CB_ADDSTRING,0,
  359.             (LONG)(pszMethod+1));
  360.         SendDlgItemMessage(hDlg,IDC_CHOICES,CB_SETITEMDATA,wLoop,
  361.             (DWORD)wTemp);
  362.         /* If we have the correct item, keep a copy so we can select it
  363.             out of the combo box... */
  364.         // check for filename only as well as full path name
  365.         if( !lstrcmpi( FileName( aszFiles[ wTemp ] ),
  366.                        FileName( szSaverName       ) ) )
  367.         {
  368.             wMethod = wTemp;
  369.             lstrcpy(szBuffer, pszMethod + 1);
  370.         }
  371.     }
  372.     if (!ScreenSaveActive)
  373.         wMethod = -1;
  374.     /* Attempt to select the string we recieved from the
  375.         system.ini entry.  If there is no match, select the
  376.         first item from the list... */
  377.     if ((wMethod == -1) || (wNumMethods == 0))
  378.     {
  379.         fContinue = TRUE;
  380.         //
  381.         // fix pszMethod not being init'd when no .SCR
  382.         // files are found anywhere (this is a hack because
  383.         // I don't want to figure this garbage out)
  384.         //  THIS ISN'T NEEDED!  NO MORE FORWARD REFERENCES TO IT!
  385.         //  pszMethod = g_szNULL;
  386.     }
  387.     else
  388.     {
  389.         if (SendDlgItemMessage(hDlg, IDC_CHOICES, CB_SELECTSTRING, (WPARAM)-1,
  390.             (LONG)szBuffer) == CB_ERR)
  391.             fContinue = TRUE;
  392.         else
  393.             fContinue = FALSE;
  394.     }
  395.     if(fContinue)
  396.     {
  397.        SendDlgItemMessage(hDlg,IDC_CHOICES,CB_SETCURSEL,0,0l);
  398.        lstrcpy(szSaverName,g_szNULL);
  399.        wMethod = -1;
  400.     }
  401.     g_hbmDemo = LoadMonitorBitmap( TRUE );
  402.     if (g_hbmDemo) 
  403.         SendDlgItemMessage(hDlg,IDC_BIGICON,STM_SETIMAGE, IMAGE_BITMAP,(DWORD)g_hbmDemo);
  404. #ifndef WINNT
  405.     g_fAdapPwrMgnt = QueryAdapterPwrMgnt();
  406. #else
  407.     //BUGBUG - put this back in once we get the power management stuff worked out
  408.     //  07-Apr-1995 JonPa
  409. //#pragma message( __FILE__"(443): warning !!!! : remove this #ifdef when user implements api" )
  410.     g_fAdapPwrMgnt = FALSE;
  411. #endif
  412.     g_hbmEnergyStar = LoadImage( hInstance, MAKEINTRESOURCE( IDB_ENERGYSTAR ),
  413.         IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS );
  414.     if( g_hbmEnergyStar )
  415.     {
  416.         SendDlgItemMessage( hDlg, IDC_ENERGYSTAR_BMP, STM_SETIMAGE,
  417.             IMAGE_BITMAP, (LPARAM)g_hbmEnergyStar );
  418.     }
  419.     // Hide/Disable the energy related controls if the adaptor/monitor does not
  420.     // support power mgnt.
  421.     EnableDisablePowerDelays(hDlg);
  422.     // initialize the password checkbox
  423.     if (RegOpenKey(HKEY_CURRENT_USER,REGSTR_PATH_SCREENSAVE,&hKey) == ERROR_SUCCESS) {
  424.         if (IsPasswdSecure(hKey, SZ_USE_PASSWORD ))
  425.             g_fPasswordWasPreviouslyEnabled = TRUE;
  426.         RegCloseKey(hKey);
  427.     }
  428.     // subclass the static control so we can synchronize painting
  429.     hwnd = GetDlgItem(hDlg, IDC_BIGICON);
  430.     if (hwnd)
  431.     {
  432.         g_lpOldStaticProc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
  433.         SetWindowLong(hwnd, GWL_WNDPROC, (LONG)(WNDPROC)StaticSubclassProc);
  434.     }
  435.     return TRUE;
  436. }
  437. void NEAR PASCAL SetNewSSDemo(HWND hDlg, int iMethod)
  438. {
  439.     HBITMAP hbmOld;
  440.     POINT ptIcon;
  441.     HWND hwndDemo;
  442.     HWND hwndC;
  443.     HICON hicon;
  444.     RECT rc = {MON_X, MON_Y, MON_X+MON_DX, MON_Y+MON_DY};
  445.     hwndDemo = GetSSDemoParent( hDlg );
  446.     // blank out the background with dialog color
  447.     hbmOld = SelectObject(g_hdcMem, g_hbmDemo);
  448.     FillRect(g_hdcMem, &rc, GetSysColorBrush(COLOR_DESKTOP));
  449.     SelectObject(g_hdcMem, hbmOld);
  450.     // kill the old one dammit kill it kill it kill kill kill
  451.     while( hwndC = GetWindow( hwndDemo, GW_CHILD ) )
  452.         SendMessage(hwndC, WM_CLOSE, 0, 0);
  453.     Yield(); // paranoid
  454.     Yield(); // really paranoid
  455.     ShowWindow(hwndDemo, SW_HIDE);
  456.     g_fPreviewActive = FALSE;
  457.     if (iMethod >= 0 && aszMethods[iMethod][0] == TEXT('P'))
  458.     {
  459.         RECT rc;
  460.         BITMAP bm;
  461.         UpdateWindow(hDlg);
  462.         //UpdateWindow(GetDlgItem(hDlg, IDC_BIGICON));
  463.         GetObject(g_hbmDemo, sizeof(bm), &bm);
  464.         GetClientRect(GetDlgItem(hDlg, IDC_BIGICON), &rc);
  465.         rc.left = ( rc.right - bm.bmWidth ) / 2 + MON_X;
  466.         rc.top = ( rc.bottom - bm.bmHeight ) / 2 + MON_Y;
  467.         MoveWindow(hwndDemo, rc.left, rc.top, MON_DX, MON_DY, FALSE);
  468.         wsprintf(szBuffer, TEXT("%s /p %d"), szSaverName, hwndDemo);
  469.         if (WinExecN(szBuffer, SW_NORMAL) > 32)
  470.         {
  471.             ShowWindow(hwndDemo, SW_SHOWNA);
  472.             g_fPreviewActive = TRUE;
  473.             return;
  474.         }
  475.     }
  476.     if (iMethod != -1)
  477.     {
  478.         ptIcon.x = GetSystemMetrics(SM_CXICON);
  479.         ptIcon.y = GetSystemMetrics(SM_CYICON);
  480.         // draw the icon double size
  481.         Assert(ptIcon.y*2 <= MON_DY);
  482.         Assert(ptIcon.x*2 <= MON_DX);
  483.         hicon = hIcons[iMethod];
  484.         if (hicon == NULL && aszMethods[iMethod][0] == TEXT('I'))
  485.             hicon = hIdleWildIcon;
  486.         if (hicon == NULL)
  487.             hicon = hDefaultIcon;
  488.         hbmOld = SelectObject(g_hdcMem, g_hbmDemo);
  489.         DrawIconEx(g_hdcMem,
  490.             MON_X + (MON_DX-ptIcon.x*2)/2,
  491.             MON_Y + (MON_DY-ptIcon.y*2)/2,
  492.             hicon, ptIcon.x*2, ptIcon.y*2, 0, NULL, DI_NORMAL);
  493.         SelectObject(g_hdcMem, hbmOld);
  494.     }
  495.     InvalidateRect(GetDlgItem(hDlg, IDC_BIGICON), NULL, FALSE);
  496. }
  497. static void NEAR PASCAL SS_SomethingChanged(HWND hDlg)
  498. {
  499.     if (!g_bInitSS)
  500.     {
  501.         SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  502.     }
  503. }
  504. static void NEAR PASCAL SetScreenSaverPassword(HWND hDlg, int iMethod)
  505. {
  506.     if (iMethod >= 0 && aszMethods[iMethod][0] == TEXT('P'))
  507.     {
  508.         wsprintf(szBuffer, TEXT("%s /a %u"), szSaverName, GetParent(hDlg));
  509.         WinExecN(szBuffer, SW_NORMAL);
  510.     }
  511. }
  512. BOOL APIENTRY  ScreenSaverDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  513. {
  514.     NMHDR FAR *lpnm;
  515.     PTSTR  pszMethod;
  516.     int   wTemp;
  517.     int   wMethod;
  518.     BOOL  fEnable;
  519.     switch(message)
  520.     {
  521.         case WM_NOTIFY:
  522.             lpnm = (NMHDR FAR *)lParam;
  523.             switch(lpnm->code)
  524.             {
  525.                 case PSN_APPLY:
  526.                     /* Make sure the time we have is the last one entered... */
  527.                     SendMessage(hDlg, WM_COMMAND, MAKELONG( IDC_SCREENSAVEDELAY, EN_KILLFOCUS),
  528.                             (LPARAM)GetDlgItem(hDlg, IDC_SCREENSAVEDELAY));
  529.                     /* Try to save the current settings... */
  530.                     SaveIni(hDlg);
  531.                     /////RETTRUE(hDlg)
  532.                     break;
  533.                 // nothing to do on cancel...
  534.                 case PSN_RESET:
  535.                     if (g_fPreviewActive)
  536.                         SetNewSSDemo(hDlg, -1);
  537.                     break;
  538.                 case PSN_KILLACTIVE:
  539.                     if (g_fPreviewActive)
  540.                         SetNewSSDemo(hDlg, -1);
  541.                     break;
  542.                 case PSN_SETACTIVE:
  543.                     EnableDisablePowerDelays(hDlg);
  544.                     if (!g_fPreviewActive)
  545.                     {
  546.                         g_bInitSS = TRUE;
  547.                         SendMessage(hDlg, WM_COMMAND, MAKELONG(IDC_CHOICES, CBN_SELCHANGE),
  548.                                     (LPARAM)GetDlgItem(hDlg, IDC_CHOICES));
  549.                         g_bInitSS = FALSE;
  550.                     }
  551.                     break;
  552.             }
  553.             break;
  554.         case WM_INITDIALOG:
  555.             g_bInitSS = TRUE;
  556.             InitSSDialog(hDlg);
  557.             g_bInitSS = FALSE;
  558.             break;
  559.         case WM_DISPLAYCHANGE:
  560.         case WM_SYSCOLORCHANGE: {
  561.             HBITMAP hbm;
  562.             hbm = g_hbmDemo;
  563.             g_hbmDemo = LoadMonitorBitmap( TRUE );
  564.             if (g_hbmDemo) {
  565.                 // Got a new bitmap, use it and delete the old one.
  566.                 SendDlgItemMessage(hDlg,IDC_BIGICON,STM_SETIMAGE, IMAGE_BITMAP,(DWORD)g_hbmDemo);
  567.                 if (hbm) {
  568.                     DeleteObject(hbm);
  569.                 }
  570.             } else {
  571.                 // Couldn't get a new bitmap, just reuse the old one
  572.                 g_hbmDemo = hbm;
  573.             }
  574.             break;
  575.         }
  576.         case WM_DESTROY:
  577.             FreeScrEntries();
  578.             if (g_fPreviewActive)
  579.                 SetNewSSDemo(hDlg, -1);
  580.             if (g_hbmDemo)
  581.             {
  582.                 SendDlgItemMessage(hDlg,IDC_BIGICON,STM_SETIMAGE,IMAGE_BITMAP,
  583.                     (LPARAM)NULL);
  584.                 DeleteObject(g_hbmDemo);
  585.             }
  586.             if (g_hbmEnergyStar)
  587.             {
  588.                 SendDlgItemMessage(hDlg,IDC_ENERGYSTAR_BMP,STM_SETIMAGE,
  589.                     IMAGE_BITMAP, (LPARAM)NULL);
  590.                 DeleteObject(g_hbmEnergyStar);
  591.             }
  592.             break;
  593.         case WM_VSCROLL:
  594.             if (LOWORD(wParam) == SB_THUMBPOSITION)
  595.                 ScreenSaver_AdjustTimeouts(hDlg, GetDlgCtrlID((HWND)lParam) - BCI_ARROW);
  596.             break;
  597.         case WM_HELP:
  598.             WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL,
  599.                 HELP_WM_HELP, (DWORD)aSaverHelpIds);
  600.             break;
  601.         case WM_CONTEXTMENU:      // right mouse click
  602.             WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
  603.                 (DWORD) aSaverHelpIds);
  604.             break;
  605.         case WM_QUERYNEWPALETTE:
  606.         case WM_PALETTECHANGED:
  607.             ForwardSSDemoMsg(hDlg, message, wParam, lParam);
  608.             break;
  609.             
  610.         case WM_COMMAND:
  611.             switch(LOWORD(wParam))
  612.             {
  613.                 /* Check for a selection change in the combo box. If there is
  614.                     one, then update the method number as well as the
  615.                     configure button... */
  616.                 case IDC_CHOICES:
  617.                     if(HIWORD(wParam) == CBN_SELCHANGE)
  618.                     {
  619.                         /* Dump the name of the current selection into
  620.                             the buffer... */
  621.                         wTemp = SendDlgItemMessage(hDlg,IDC_CHOICES,
  622.                             CB_GETCURSEL,0,0l);
  623.                         if(wTemp)
  624.                         {
  625.                             wMethod = SendDlgItemMessage(hDlg,IDC_CHOICES,
  626.                                 CB_GETITEMDATA,wTemp,0l);
  627.                             /* Grey the button accordingly... */
  628.                             pszMethod = aszMethods[wMethod];
  629.                             if(pszMethod[0] == TEXT('C') ||       // can config
  630.                                pszMethod[0] == TEXT('I') ||       // IdleWild
  631.                                pszMethod[0] == TEXT('P') )        // can preview
  632.                                 EnableDlgItem(hDlg,IDC_SETTING, TRUE);
  633.                             else
  634.                                 EnableDlgItem(hDlg,IDC_SETTING, FALSE);
  635. #ifndef WINNT   // All screen savers on NT can use password protection
  636.                             if(pszMethod[0] == TEXT('P'))         // is a Win32 4.0 saver
  637.                             {
  638. #endif
  639.                                 EnableDlgItem(hDlg,IDC_USEPASSWORD, TRUE);
  640.                                 CheckDlgButton( hDlg, IDC_USEPASSWORD,
  641.                                     g_fPasswordWasPreviouslyEnabled );
  642.                                 EnableDisableSetPasswordBtn(hDlg);
  643. #ifndef WINNT   // All screen savers on NT can use password protection
  644.                             }
  645.                             else
  646.                             {
  647.                                 g_fPasswordWasPreviouslyEnabled =
  648.                                     IsDlgButtonChecked( hDlg, IDC_USEPASSWORD );
  649.                                 CheckDlgButton( hDlg, IDC_USEPASSWORD, FALSE );
  650.                                 EnableDlgItem(hDlg,IDC_USEPASSWORD,FALSE);
  651.                                 EnableDlgItem(hDlg,IDC_SETPASSWORD,FALSE);
  652.                             }
  653. #endif
  654.                             /* For fun, create an extra copy of
  655.                                 szSaverName... */
  656.                             pszMethod = aszFiles[wMethod];
  657.                             lstrcpy(szSaverName,pszMethod);
  658.                             fEnable = TRUE;
  659.                         }
  660.                         else
  661.                         {
  662.                             wMethod = -1;
  663.                             lstrcpy(szSaverName, g_szNULL);
  664.                             EnableDlgItem(hDlg,IDC_SETTING,FALSE);
  665.                             EnableDlgItem(hDlg,IDC_USEPASSWORD,FALSE);
  666. #ifndef WINNT
  667.                             EnableDlgItem(hDlg,IDC_SETPASSWORD,FALSE);
  668. #endif
  669.                             fEnable = FALSE;
  670.                         }
  671.                         //  Following are enabled as a group... (oh really?)
  672.                         EnableDlgItem(hDlg,IDC_SSDELAYLABEL,fEnable);
  673.                         EnableDlgItem(hDlg,IDC_SCREENSAVEDELAY,fEnable);
  674.                         EnableDlgItem(hDlg,IDC_SCREENSAVEARROW,fEnable);
  675.                         EnableDlgItem(hDlg,IDC_SSDELAYSCALE,fEnable);
  676.                         EnableDlgItem(hDlg,IDC_TEST,fEnable);
  677.                         g_iMethod = (int)wMethod;
  678.                         SetNewSSDemo(hDlg, wMethod);
  679.                         SS_SomethingChanged(hDlg);
  680.                     }
  681.                     break;
  682.                 /* If the edit box loses focus, translate... */
  683.                 case IDC_SCREENSAVEDELAY:
  684.                 case IDC_LOWPOWERDELAY:
  685.                 case IDC_POWEROFFDELAY:
  686.                     if (HIWORD(wParam) == EN_KILLFOCUS)
  687.                         ScreenSaver_AdjustTimeouts(hDlg, LOWORD(wParam));
  688.                     break;
  689.                 case IDC_LOWPOWERSWITCH:
  690.                 case IDC_POWEROFFSWITCH:
  691.                     if (HIWORD(wParam) == BN_CLICKED) {
  692.                         ScreenSaver_EnableDisableDelays(hDlg, (int) LOWORD(wParam) -
  693.                             BCI_SWITCH);
  694.                         SS_SomethingChanged(hDlg);
  695.                     }
  696.                     break;
  697.                 /* If the user wishes to test... */
  698.                  case IDC_TEST:
  699.                     switch( HIWORD( wParam ) )
  700.                     {
  701.                         case BN_CLICKED:
  702.                         DoScreenSaver(hDlg,TRUE);
  703.                         break;
  704.                     }
  705.                     break;
  706.                 /* Tell the DLL that it can do the configure... */
  707.                 case IDC_SETTING:
  708.                 if (HIWORD(wParam) == BN_CLICKED) {
  709.                     DoScreenSaver(hDlg,FALSE);
  710.                     break;
  711.                 }
  712.                 case IDC_USEPASSWORD:
  713.                 if (HIWORD(wParam) == BN_CLICKED) {
  714.                     g_fPasswordWasPreviouslyEnabled =
  715.                         IsDlgButtonChecked( hDlg, IDC_USEPASSWORD );
  716.                     EnableDisableSetPasswordBtn(hDlg);
  717.                     SS_SomethingChanged(hDlg);
  718.                     break;
  719.                 }
  720.                 case IDC_SETPASSWORD:
  721.                 if (HIWORD(wParam) == BN_CLICKED) {
  722.                     // ask new savers to change passwords
  723.                     wTemp = SendDlgItemMessage(hDlg,IDC_CHOICES,
  724.                         CB_GETCURSEL,0,0l);
  725.                     if(wTemp)
  726.                     {
  727.                         SetScreenSaverPassword(hDlg,
  728.                             (int)SendDlgItemMessage(hDlg,IDC_CHOICES,
  729.                             CB_GETITEMDATA,wTemp,0l));
  730.                     }
  731.                     break;
  732.                 }
  733.             }
  734.             break;
  735.         case WM_CTLCOLORSTATIC:
  736.             if( (HWND)lParam == GetSSDemoParent( hDlg ) )
  737.             {
  738.                 return (BOOL)GetStockObject( NULL_BRUSH );
  739.             }
  740.             break;
  741.     }
  742.     return FALSE;
  743. }
  744. /*******************************************************************************
  745. *
  746. *  ScreenSaver_AdjustTimeouts
  747. *
  748. *  DESCRIPTION:
  749. *     Called whenever the user adjusts the delay of one of the time controls.
  750. *     Adjusts the delays of the other time controls such that the screen saver
  751. *     delay is less than the low power delay and that the low power delay is
  752. *     less than the power off delay.
  753. *
  754. *  PARAMETERS:
  755. *     hWnd, handle of ScreenSaver window.
  756. *     BaseControlID, base control ID of the radio, edit, and arrow time control
  757. *        combination.
  758. *
  759. *******************************************************************************/
  760. VOID
  761. NEAR PASCAL
  762. ScreenSaver_AdjustTimeouts(
  763.     HWND hWnd,
  764.     int BaseControlID
  765.     )
  766. {
  767.     BOOL fTranslated;
  768.     int Timeout;
  769.     int NewTimeout;
  770.     //
  771.     //  Get the new timeout for this time control and validate it's contents.
  772.     //
  773.     Timeout = (int) GetDlgItemInt(hWnd, BaseControlID + BCI_DELAY, &fTranslated,
  774.         FALSE);
  775.     Timeout = min(max(Timeout, 1), MAX_MINUTES);
  776.     SetDlgItemInt(hWnd, BaseControlID + BCI_DELAY, (UINT) Timeout, FALSE);
  777.     //
  778.     //  Check the new value of this time control against the other timeouts,
  779.     //  adjust their values if necessary.  Be careful when changing the order
  780.     //  of these conditionals.
  781.     //
  782.     if (BaseControlID == IDC_SCREENSAVEDELAY) {
  783.         if (g_Timeout[TA_SCREENSAVE] != Timeout) {
  784.             g_Timeout[TA_SCREENSAVE] = Timeout;
  785.             SS_SomethingChanged(hWnd);
  786.         }
  787.     }
  788.     else {
  789.         if (Timeout < g_Timeout[TA_SCREENSAVE]) {
  790.             g_Timeout[TA_SCREENSAVE] = Timeout;
  791.             SetDlgItemInt(hWnd, IDC_SCREENSAVEDELAY, (UINT) Timeout, FALSE);
  792.         }
  793.     }
  794.     if (BaseControlID == IDC_POWEROFFDELAY) {
  795.         if (g_Timeout[TA_POWEROFF] != Timeout) {
  796.             g_Timeout[TA_POWEROFF] = Timeout;
  797.             SS_SomethingChanged(hWnd);
  798.         }
  799.     }
  800.     else {
  801.         if (Timeout > g_Timeout[TA_POWEROFF]) {
  802.             g_Timeout[TA_POWEROFF] = Timeout;
  803.             SetDlgItemInt(hWnd, IDC_POWEROFFDELAY, (UINT) Timeout, FALSE);
  804.         }
  805.     }
  806.     if (BaseControlID == IDC_LOWPOWERDELAY) {
  807.         if (g_Timeout[TA_LOWPOWER] != Timeout) {
  808.             g_Timeout[TA_LOWPOWER] = Timeout;
  809.             SS_SomethingChanged(hWnd);
  810.         }
  811.     }
  812.     else {
  813.         NewTimeout = min(max(g_Timeout[TA_LOWPOWER], g_Timeout[TA_SCREENSAVE]),
  814.             g_Timeout[TA_POWEROFF]);
  815.         if (NewTimeout != g_Timeout[TA_LOWPOWER]) {
  816.             g_Timeout[TA_LOWPOWER] = Timeout;
  817.             SetDlgItemInt(hWnd, IDC_LOWPOWERDELAY, (UINT) NewTimeout, FALSE);
  818.         }
  819.     }
  820. }
  821. /*******************************************************************************
  822. *
  823. *  ScreenSaver_EnableDisableDelays
  824. *
  825. *  DESCRIPTION:
  826. *     Called whenever the user clicks one of the time controls.  Enables or
  827. *     disables the "buddy" edit and arrow controls.
  828. *
  829. *  PARAMETERS:
  830. *     hWnd, handle of ScreenSaver window.
  831. *     BaseControlID, base control ID of the radio, edit, and arrow time control
  832. *        combination.
  833. *
  834. *******************************************************************************/
  835. void NEAR PASCAL ScreenSaver_EnableDisableDelays(HWND hWnd,int BaseControlID)
  836. {
  837.     BOOL fEnable;
  838.     fEnable = (IsDlgButtonChecked(hWnd, BaseControlID + BCI_SWITCH) == 1);
  839.     EnableDlgItem(hWnd, BaseControlID + BCI_DELAY, fEnable);
  840.     EnableDlgItem(hWnd, BaseControlID + BCI_ARROW, fEnable);
  841. }
  842. void NEAR PASCAL EnableDisablePowerDelays(HWND hDlg)
  843. {
  844.     int i;
  845.     BOOL fDPMS;
  846.     static idCtrls[] = { IDC_ENERGY_TEXT,
  847.                          IDC_ENERGY_TEXT2,
  848.                          IDC_ENERGY_TEXT3,
  849.                          IDC_ENERGYSTAR_BMP,
  850.                          IDC_LOWPOWERDELAY+BCI_DELAY,
  851.                          IDC_LOWPOWERDELAY+BCI_ARROW,
  852.                          IDC_LOWPOWERDELAY+BCI_SWITCH,
  853.                          IDC_POWEROFFDELAY+BCI_DELAY,
  854.                          IDC_POWEROFFDELAY+BCI_ARROW,
  855.                          IDC_POWEROFFDELAY+BCI_SWITCH,
  856.                          0 };
  857.     for (i = 0; idCtrls[i] != 0; i++)
  858.         ShowWindow( GetDlgItem( hDlg, idCtrls[i] ), g_fAdapPwrMgnt ? SW_SHOWNA : SW_HIDE );
  859.     if( g_fAdapPwrMgnt )
  860.     {
  861. #ifdef LATER
  862.         //11-Jul-1995 JonPa BUGBUG use this when we get DPMS for NT
  863.         fDPMS = GetMonitorDPMS();
  864. #else
  865.         fDPMS = FALSE;
  866. #endif
  867.         // Enable/Disable the power related timer switches based on Monitor
  868.         // DPMS capability
  869.         EnableDlgItem(hDlg,IDC_ENERGY_TEXT, fDPMS);
  870.         EnableDlgItem(hDlg,IDC_LOWPOWERDELAY+BCI_SWITCH, fDPMS);
  871.         EnableDlgItem(hDlg,IDC_POWEROFFDELAY+BCI_SWITCH, fDPMS);
  872.         // If DPMS compliant, enable/disable the other power timer values
  873.         // based on the switch setting, otherwise disable everything
  874.         if (fDPMS)
  875.         {
  876.             ScreenSaver_EnableDisableDelays(hDlg,IDC_LOWPOWERDELAY);
  877.             ScreenSaver_EnableDisableDelays(hDlg,IDC_POWEROFFDELAY);
  878.         }
  879.         else
  880.         {
  881.             EnableDlgItem(hDlg,IDC_LOWPOWERDELAY+BCI_DELAY, FALSE);
  882.             EnableDlgItem(hDlg,IDC_LOWPOWERDELAY+BCI_ARROW, FALSE);
  883.             EnableDlgItem(hDlg,IDC_POWEROFFDELAY+BCI_DELAY, FALSE);
  884.             EnableDlgItem(hDlg,IDC_POWEROFFDELAY+BCI_ARROW, FALSE);
  885.         }
  886.     }
  887. }
  888. // keep the "set password" button enabled/disabled
  889. // according to whether "use password" is checked or not
  890. void NEAR PASCAL EnableDisableSetPasswordBtn(HWND hDlg)
  891. {
  892.     BOOL fEnable = IsDlgButtonChecked( hDlg,IDC_USEPASSWORD );
  893. #ifndef WINNT
  894.     EnableDlgItem( hDlg, IDC_SETPASSWORD, fEnable );
  895. #endif
  896. }
  897. /* This routine will search for entries that are screen savers.  The directory
  898.     searched is either the system directory (.. */
  899. void NEAR PASCAL SearchForScrEntries(UINT wDir, LPCTSTR file)
  900. {
  901.     TCHAR szPath[MAX_PATH];
  902.     TCHAR szPath2[MAX_PATH];
  903.     HANDLE hfind;
  904.     WIN32_FIND_DATA fd;
  905.     // don't do any work if no space left
  906.     if( wNumMethods >= MAX_METHODS )
  907.         return;
  908.     /* Get the directory where the program resides... */
  909.     GetModuleFileName(hInstance, szPath, ARRAYSIZE(szPath));
  910.     StripPathName(szPath);
  911.     switch ( wDir )
  912.     {
  913.         case SFSE_WINDOWS:
  914.             /* Search the windows directory and place the path with the  in
  915.                 the szPath variable... */
  916.             GetWindowsDirectory(szPath2, ARRAYSIZE(szPath2));
  917. sfseSanityCheck:
  918.             /* if same dir as where it was launched, don't search again */
  919.             if (!lstrcmpi(szPath, szPath2))
  920.                return;
  921.             lstrcpy(szPath, szPath2);
  922.             break;
  923.         case SFSE_SYSTEM:
  924.             /* Search the system directory and place the path with the  in
  925.                 the szPath variable... */
  926.             GetSystemDirectory(szPath2, ARRAYSIZE(szPath2));
  927.             goto sfseSanityCheck;
  928.         case SFSE_FILE:
  929.             /* Search the directory containing 'file' */
  930.             lstrcpy(szPath2, file);
  931.             StripPathName(szPath2);
  932.             goto sfseSanityCheck;
  933.     }
  934.     AppendPath(szPath, TEXT("*.scr"));
  935.     if( ( hfind = FindFirstFile( szPath, &fd ) ) != INVALID_HANDLE_VALUE )
  936.     {
  937.         StripPathName(szPath);
  938.         do
  939.         {
  940.             PTSTR pszDesc;
  941.             BOOL fLFN;
  942.             fLFN = !(fd.cAlternateFileName[0] == 0 ||
  943.                     lstrcmp(fd.cFileName, fd.cAlternateFileName) == 0);
  944.             lstrcpy(szPath2, szPath);
  945.             AppendPath(szPath2, fd.cFileName);
  946.             // Note: PerformCheck does an alloc
  947.             if( ( pszDesc = PerformCheck( szPath2, fLFN ) ) != NULL )
  948.             {
  949.                 BOOL bAdded = FALSE;
  950.                 UINT i;
  951.                 for( i = 0; i < wNumMethods; i++ )
  952.                 {
  953.                     if( !lstrcmpi( pszDesc, aszMethods[ i ] ) )
  954.                     {
  955.                         bAdded = TRUE;
  956.                         break;
  957.                     }
  958.                 }
  959.                 if( !bAdded )
  960.                 {
  961.                     PTSTR pszEntries;
  962.                     // COMPATIBILITY: always use short name
  963.                     // otherwise some apps fault when peeking at SYSTEM.INI
  964.                     if( fLFN )
  965.                     {
  966.                         lstrcpy(szPath2, szPath);
  967.                         AppendPath(szPath2, fd.cAlternateFileName);
  968.                     }
  969.                     if( ( pszEntries = AllocStr( szPath2 ) ) != NULL )
  970.                     {
  971.                         if (pszDesc[0] != TEXT('P'))
  972.                             hIcons[wNumMethods] = ExtractIcon(hInstance, szPath2, 0);
  973.                         else
  974.                             hIcons[wNumMethods] = NULL;
  975.                         aszMethods[wNumMethods] = pszDesc;
  976.                         aszFiles[wNumMethods] = pszEntries;
  977.                         wNumMethods++;
  978.                         bAdded = TRUE;
  979.                     }
  980.                 }
  981.                 if( !bAdded )
  982.                     LocalFree((HLOCAL)pszDesc);
  983.             }
  984.         } while( FindNextFile( hfind, &fd ) && ( wNumMethods < MAX_METHODS ) );
  985.         FindClose(hfind);
  986.     }
  987.     return;
  988. }
  989. //
  990. //  This routine checks a given file to see if it is indeed a screen saver
  991. //  executable...
  992. //
  993. //  a valid screen saver exe has the following description line:
  994. //
  995. //      SCRNSAVE [c] : description :
  996. //
  997. //      SCRNSAVE is a required name that indicates a screen saver.
  998. //
  999. PTSTR NEAR PASCAL PerformCheck(LPTSTR lpszFilename, BOOL fLFN)
  1000. {
  1001.     int  i;
  1002.     TCHAR chConfig=TEXT('C');       // assume configure
  1003.     LPTSTR pch;
  1004.     DWORD dw;
  1005.     WORD  Version;
  1006.     WORD  Magic;
  1007.     /* Get the description... */
  1008.     pch = szBuffer + 1;
  1009.     //
  1010.     //  if we have a LFN (Long File Name) dont bother getting the
  1011.     //  exe descrription
  1012.     //
  1013.     dw = GetExeInfo(lpszFilename, pch, ARRAYSIZE(szBuffer)-1, fLFN ? GEI_EXPVER : GEI_DESCRIPTION);
  1014.     Version = HIWORD(dw);
  1015.     Magic   = LOWORD(dw);
  1016.     if (dw == 0)
  1017.         return NULL;
  1018.     if (Magic == PEMAGIC || fLFN)
  1019.     {
  1020.         BOOL fGotName = FALSE;
  1021.         if (!fLFN) {
  1022.             HANDLE  hSaver;
  1023.             //
  1024.             // We have a 32 bit screen saver with a short name, look for an NT style
  1025.             // decription in it's string table
  1026.             //
  1027.             if (hSaver = LoadLibrary (lpszFilename)) {
  1028.                 if (LoadString (hSaver, IDS_DESCRIPTION, pch, ARRAYSIZE(szBuffer) - (szBuffer - pch))) {
  1029.                     fGotName = TRUE;
  1030.                 }
  1031.                 FreeLibrary (hSaver);
  1032.             }
  1033.         }
  1034.         if (!fGotName) {
  1035.             //
  1036.             //  we have a LFN (LongFileName) or a Win32 screen saver,
  1037.             //  Win32 exe's in general dont have a description field so
  1038.             //  we assume they can configure.  We also try to build
  1039.             //  a "nice" name for it.
  1040.             //
  1041.             lstrcpy(pch, lpszFilename);
  1042.             pch = FileName(pch);                    // strip path part
  1043.             if ( ((TCHAR)CharUpper((LPTSTR)(pch[0]))) == TEXT('S') && ((TCHAR)CharUpper((LPTSTR)(pch[1]))) == TEXT('S'))     // map SSBEZIER.SCR to BEZIER.SCR
  1044.                 pch+=2;
  1045.             pch = NiceName(pch);                    // map BEZIER.SCR to Bezier
  1046.         }
  1047.     }
  1048.     else
  1049.     {
  1050.         LPTSTR pchTemp;
  1051.         //
  1052.         //  we have a 8.3 file name 16bit screen saveer, parse the
  1053.         //  description string from the exehdr
  1054.         //
  1055.         /* Check to make sure that at least the 11 characters needed for info
  1056.             are there... */
  1057.         if (lstrlen(pch) < 9)
  1058.             return NULL;
  1059.         /* Check the first 8 characters for the string... */
  1060.         if (lstrncmp(TEXT("SCRNSAVE"), pch, 8))
  1061.             return NULL;
  1062.         // If successful, allocate enough space for the string and copy the
  1063.         // string to the new one...
  1064.         pch = pch + 8;                 // skip over 'SCRNSAVE'
  1065.         while (*pch==TEXT(' '))                   // advance over white space
  1066.             pch++;
  1067.         if (*pch==TEXT('C') || *pch==TEXT('c'))         // parse the configure flag
  1068.         {
  1069.             chConfig = TEXT('C');
  1070.             pch++;
  1071.         }
  1072.         if (*pch==TEXT('X') || *pch==TEXT('x'))         // parse the don't configure flag
  1073.             chConfig = *pch++;
  1074.         // we might be pointing at a name or separation goop
  1075.         pchTemp = pch;                      // remember this spot
  1076.         while (*pch && *pch!=TEXT(':'))           // find separator
  1077.             pch++;
  1078.         while (*pch==TEXT(':') || *pch==TEXT(' '))      // advance over whtspc/last colon
  1079.             pch++;
  1080.         // if we haven't found a name yet fall back on the saved location
  1081.         if (!*pch)
  1082.             pch = pchTemp;
  1083.         while (*pch==TEXT(':') || *pch==TEXT(' '))      // re-advance over whtspc
  1084.             pch++;
  1085.         /* In case the screen saver has version information information
  1086.             embedded after the name, check to see if there is a colon TEXT(':')
  1087.             in the description and replace it with a NULL... */
  1088.         for (i=0; pch[i]; i++)              //
  1089.         {
  1090. #ifdef DBCS
  1091.             if (IsDBCSLeadByte(pch[i]))
  1092.             {
  1093.                 i++;
  1094.             }
  1095.             else
  1096. #endif
  1097.             if (pch[i]==TEXT(':'))
  1098.                 pch[i]=0;
  1099.         }
  1100. // Space is OK for DBCS (FE)
  1101.         while(i>0 && pch[i-1]==TEXT(' '))         // remove trailing space
  1102.             pch[--i]=0;
  1103.     }
  1104. #ifdef DEBUG
  1105.     if (Magic == PEMAGIC)
  1106.         lstrcat(pch, TEXT(" (32-bit)"));          // add techy stuff.
  1107.     else
  1108.         lstrcat(pch, TEXT(" (16-bit)"));
  1109.     if (Version == 0x030A)
  1110.         lstrcat(pch, TEXT(" (3.10)"));
  1111.     if (Version == 0x0400)
  1112.         lstrcat(pch, TEXT(" (4.00)"));
  1113. #endif
  1114.     //
  1115.     // assume any Win32 4.0 screen saver can do Preview mode
  1116.     //
  1117.     if (chConfig == TEXT('C') && Version >= 0x0400 && Magic == PEMAGIC)
  1118.         chConfig = TEXT('P');                     // mark as configurable/preview
  1119.     pch[-1] = chConfig;
  1120.     return AllocStr(pch-1);
  1121. }
  1122. BOOL NEAR PASCAL FreeScrEntries( void )
  1123. {
  1124.     UINT wLoop;
  1125.     for(wLoop = 0; wLoop < wNumMethods; wLoop++)
  1126.     {
  1127.         if(aszMethods[wLoop] != NULL)
  1128.             LocalFree((HANDLE)aszMethods[wLoop]);
  1129.         if(aszFiles[wLoop] != NULL)
  1130.             LocalFree((HANDLE)aszFiles[wLoop]);
  1131.         if(hIcons[wLoop] != NULL)
  1132.             FreeResource(hIcons[wLoop]);
  1133.     }
  1134.     if (hDefaultIcon)
  1135.         FreeResource(hDefaultIcon);
  1136.     if (hIdleWildIcon)
  1137.         FreeResource(hIdleWildIcon);
  1138.     hDefaultIcon=hIdleWildIcon=NULL;
  1139.     wNumMethods = 0;
  1140.     return TRUE;
  1141. }
  1142. int NEAR PASCAL lstrncmp( LPTSTR lpszString1, LPTSTR lpszString2, int nNum )
  1143. {
  1144.     /* While we can still compare characters, compare.  If the strings are
  1145.         of different lengths, characters will be different... */
  1146.     while(nNum)
  1147.     {
  1148.         if(*lpszString1 != *lpszString2)
  1149.             return *lpszString1 - *lpszString2;
  1150.         lpszString1++;
  1151.         lpszString2++;
  1152.         nNum--;
  1153.     }
  1154.     return 0;
  1155. }
  1156. void NEAR PASCAL SaveIni(HWND hDlg )
  1157. {
  1158.     LPTSTR pszMethod;
  1159.     int  wMethod,wTemp;
  1160.     UINT Counter;
  1161.         HKEY hKey;
  1162.     /* Find the current method selection... */
  1163.     wTemp = 0;
  1164.     if(wNumMethods)
  1165.     {
  1166.         /* Dump the name of the current selection into the buffer... */
  1167.         wTemp = SendDlgItemMessage(hDlg,IDC_CHOICES,CB_GETCURSEL,0,0l);
  1168.         if(wTemp)
  1169.         {
  1170.             BOOL hasspace = FALSE;
  1171.             LPTSTR pc;
  1172.             wMethod = SendDlgItemMessage(hDlg,IDC_CHOICES,CB_GETITEMDATA,
  1173.                 wTemp,0l);
  1174.             /* Dump the method name into the buffer... */
  1175.             pszMethod = aszFiles[wMethod];
  1176.             for( pc = pszMethod; *pc; pc++ )
  1177.             {
  1178.                 if( *pc == TEXT(' ') )
  1179.                 {
  1180.                     hasspace = TRUE;
  1181.                     break;
  1182.                 }
  1183.             }
  1184.             if( hasspace )
  1185.             {
  1186.                 // if we need to add quotes we'll need two sets
  1187.                 // because GetBlahBlahProfileBlah APIs strip quotes
  1188.                 wsprintf(szBuffer,TEXT("""%s"""), pszMethod);
  1189.             }
  1190.             else
  1191.                 lstrcpy(szBuffer, pszMethod);
  1192.         }
  1193.         else
  1194.             szBuffer[0] = TEXT('');
  1195.     }
  1196.     else
  1197.         szBuffer[0] = TEXT('');
  1198.     /* Save the buffer... */
  1199.     WritePrivateProfileString(g_szBoot, szMethodName,
  1200.         (szBuffer[0] != TEXT('') ? szBuffer : NULL), g_szSystemIni);
  1201.     SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, wTemp, NULL, SPIF_UPDATEINIFILE);
  1202.     for (Counter = 0; Counter < (sizeof(g_TimeoutAssociation) /
  1203.         sizeof(TIMEOUT_ASSOCIATION)); Counter++) {
  1204.         SystemParametersInfo(g_TimeoutAssociation[Counter].taSetTimeoutAction,
  1205.             (UINT) (g_Timeout[Counter] * 60), NULL, SPIF_UPDATEINIFILE);
  1206.         if (Counter != TA_SCREENSAVE) {
  1207.             SystemParametersInfo(g_TimeoutAssociation[Counter].taSetActiveAction,
  1208.                 IsDlgButtonChecked(hDlg,
  1209.                 g_TimeoutAssociation[Counter].taBaseControlID + BCI_SWITCH),
  1210.                 NULL, SPIF_UPDATEINIFILE);
  1211.         }
  1212.     }
  1213.     // save the state of the TEXT("use password") checkbox
  1214.     if (RegCreateKey(HKEY_CURRENT_USER,REGSTR_PATH_SCREENSAVE,&hKey) == ERROR_SUCCESS) {
  1215.         RegSetValueEx(hKey,SZ_USE_PASSWORD, 0, PWRD_REG_TYPE,
  1216.             PasswdRegData(IsDlgButtonChecked(hDlg,IDC_USEPASSWORD)),
  1217.             CB_USE_PWRD_VALUE);
  1218.         RegCloseKey(hKey);
  1219.     }
  1220.     /* Broadcast a WM_WININICHANGE message... */
  1221.     SendNotifyMessage(HWND_BROADCAST, WM_WININICHANGE, 0, (LONG)g_szWindows);
  1222. }
  1223. /*
  1224.  * Thread for DoScreenSaver()
  1225.  */
  1226. typedef struct {
  1227.     HWND    hDlg;
  1228.     TCHAR   szCmdLine[1];
  1229. } SSRUNDATA, *LPSSRUNDATA;
  1230. DWORD RunScreenSaverThread( LPVOID lpv ) {
  1231.     BOOL bSvrState;
  1232.     LPSSRUNDATA lpssrd;
  1233.     HWND hwndSettings, hwndPreview;
  1234.     STARTUPINFO StartupInfo;
  1235.     PROCESS_INFORMATION ProcessInformation;
  1236.     HINSTANCE hiThd;
  1237.     TCHAR szPath[MAX_PATH];
  1238.     // Lock ourselves in mem so we don't fault if app unloads us
  1239.     GetModuleFileName(hInstance, szPath, ARRAYSIZE(szPath));
  1240.     hiThd = LoadLibrary( szPath );
  1241.     lpssrd = (LPSSRUNDATA)lpv;
  1242.     hwndSettings = GetDlgItem( lpssrd->hDlg, IDC_SETTING);
  1243.     hwndPreview  = GetDlgItem( lpssrd->hDlg, IDC_TEST);
  1244.     // Save previous screen saver state
  1245.     SystemParametersInfo( SPI_GETSCREENSAVEACTIVE,0, &bSvrState, FALSE);
  1246.     // Disable current screen saver
  1247.     if( bSvrState )
  1248.         SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,FALSE, NULL, FALSE );
  1249.     // Stop the miniture preview screen saver
  1250.     if (g_fPreviewActive)
  1251.         SetNewSSDemo( lpssrd->hDlg, -1);
  1252.     // Exec the screen saver and wait for it to die
  1253.     ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  1254.     StartupInfo.cb = sizeof(StartupInfo);
  1255.     StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  1256.     StartupInfo.wShowWindow = (WORD)SW_NORMAL;
  1257.     if (CreateProcess( NULL, lpssrd->szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInformation )){
  1258.         WaitForSingleObject( ProcessInformation.hProcess, INFINITE );
  1259.         CloseHandle(ProcessInformation.hProcess);
  1260.         CloseHandle(ProcessInformation.hThread);
  1261.     }
  1262.     // Restore Screen saver state
  1263.     if( bSvrState )
  1264.         SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, bSvrState, NULL, FALSE );
  1265.     // Restart miniture preview
  1266.     PostMessage( lpssrd->hDlg, WM_COMMAND, MAKELONG(IDC_CHOICES, CBN_SELCHANGE),
  1267.                                     (LPARAM)GetDlgItem( lpssrd->hDlg, IDC_CHOICES));
  1268.     // Enable setting and preview buttons
  1269.     EnableWindow( hwndSettings, TRUE );
  1270.     EnableWindow( hwndPreview,  TRUE );
  1271.     LocalFree( lpv );
  1272.     if (hiThd)
  1273.         FreeLibraryAndExitThread( hiThd, 0 );
  1274.     return 0;
  1275. }
  1276. /* This routine actually calls the screen saver... */
  1277. void NEAR PASCAL DoScreenSaver(HWND hWnd, BOOL fSaver )
  1278. {
  1279.     LPSSRUNDATA lpssrd;
  1280.     DWORD id;
  1281.     HANDLE hThd;
  1282.     HWND hwndSettings, hwndPreview;
  1283.     if(szSaverName[0] == TEXT(''))
  1284.         return;
  1285.     if(fSaver)
  1286.         wsprintf(szBuffer,TEXT("%s /s"), szSaverName);
  1287.     else {
  1288.         wsprintf(szBuffer,TEXT("%s /c:%lu"), szSaverName, (DWORD)hWnd);
  1289.     }
  1290.     lpssrd = LocalAlloc( LMEM_FIXED, sizeof(*lpssrd) + (lstrlen(szBuffer)+1) * sizeof(TCHAR) );
  1291.     if (lpssrd == NULL)
  1292.         return;
  1293.     lpssrd->hDlg = hWnd;
  1294.     lstrcpy( lpssrd->szCmdLine, szBuffer );
  1295.     // Disable setting and preview buttons
  1296.     hwndSettings = GetDlgItem( hWnd, IDC_SETTING);
  1297.     hwndPreview  = GetDlgItem( hWnd, IDC_TEST);
  1298.     EnableWindow( hwndSettings, FALSE );
  1299.     EnableWindow( hwndPreview,  FALSE );
  1300.     hThd = CreateThread(NULL, 0, RunScreenSaverThread, lpssrd, 0, &id);
  1301.     if (hThd != NULL) {
  1302.         CloseHandle(hThd);
  1303.     } else {
  1304.         // Exec failed, re-enable setting and preview buttons and clean up thread params
  1305.         EnableWindow( hwndSettings, TRUE );
  1306.         EnableWindow( hwndPreview,  TRUE );
  1307.         LocalFree( lpssrd );
  1308.     }
  1309. }
  1310. #define SLASH(c)     ((c) == TEXT('/') || (c) == TEXT('\'))
  1311. LPTSTR NEAR PASCAL FileName(LPTSTR szPath)
  1312. {
  1313.     LPTSTR   sz;
  1314.     for (sz=szPath; *sz; sz++)
  1315.         ;
  1316. #ifdef DBCS
  1317.     for (; sz>szPath && !SLASH(*sz) && *sz!=TEXT(':'); sz=CharPrev(szPath, sz))
  1318. #else
  1319.     for (; sz>=szPath && !SLASH(*sz) && *sz!=TEXT(':'); sz--)
  1320. #endif
  1321.         ;
  1322. #ifdef DBCS
  1323.     if ( !IsDBCSLeadByte(*sz) && (SLASH(*sz) || *sz == TEXT(':')) )
  1324.         sz = CharNext(sz);
  1325.     return  sz;
  1326. #else
  1327.     return ++sz;
  1328. #endif
  1329. }
  1330. void NEAR PASCAL AddBackslash(LPTSTR pszPath)
  1331. {
  1332. #ifdef DBCS
  1333.     LPTSTR lpsz = &pszPath[lstrlen(pszPath)];
  1334.     lpsz = CharPrev(pszPath, lpsz);
  1335.     if ( *lpsz != TEXT('\') )
  1336. #else
  1337.     if( pszPath[ lstrlen( pszPath ) - 1 ] != TEXT('\') )
  1338. #endif
  1339.         lstrcat( pszPath, TEXT("\") );
  1340. }
  1341. LPTSTR NEAR PASCAL StripPathName(LPTSTR szPath)
  1342. {
  1343.     LPTSTR   sz;
  1344. #ifdef DBCS
  1345.     LPTSTR   szFile;
  1346. #endif
  1347.     sz = FileName(szPath);
  1348. #ifdef DBCS
  1349.     szFile = sz;
  1350.     if ( szFile >szPath+1 )
  1351.     {
  1352.         szFile = CharPrev( szPath, szFile );
  1353.         if (SLASH(*szFile))
  1354.         {
  1355.             szFile = CharPrev(szPath, szFile);
  1356.             if (*szFile != TEXT(':'))
  1357.                 sz--;
  1358.         }
  1359.     }
  1360. #else
  1361.     if (sz > szPath+1 && SLASH(sz[-1]) && sz[-2] != TEXT(':'))
  1362.         sz--;
  1363. #endif
  1364.     *sz = 0;
  1365.     return szPath;
  1366. }
  1367. void NEAR PASCAL AppendPath(LPTSTR pszPath, LPTSTR pszSpec)
  1368. {
  1369.     AddBackslash(pszPath);
  1370.     lstrcat(pszPath, pszSpec);
  1371. }
  1372. PTSTR NEAR PASCAL AllocStr(LPTSTR szCopy)
  1373. {
  1374.     PTSTR sz;
  1375.     if (sz = (PTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * (lstrlen(szCopy)+1)))
  1376.         lstrcpy(sz,szCopy);
  1377.     return sz;
  1378. }
  1379. LPTSTR NEAR PASCAL NiceName(LPTSTR szPath)
  1380. {
  1381.     LPTSTR   sz;
  1382.     LPTSTR   lpsztmp;
  1383.     sz = FileName(szPath);
  1384.     for(lpsztmp = sz; *lpsztmp  && *lpsztmp != TEXT('.'); lpsztmp = CharNext(lpsztmp))
  1385.         ;
  1386.     *lpsztmp = TEXT('');
  1387.     if (IsCharUpper(sz[0]) && IsCharUpper(sz[1]))
  1388.     {
  1389.         CharLower(sz);
  1390.         CharUpperBuff(sz, 1);
  1391.     }
  1392.     return sz;
  1393. }