SCRNSAVE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:22k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4.     scrnsave.c
  5. Abstract:
  6.     This source file implements the seven required functions for a
  7.     Windows NT 5.0 migration DLL.  The DLL demonstrates how the
  8.     interface works by performing the Windows 9x screen saver 
  9.     upgrade.
  10.     The source here is a subset of the actual screen saver DLL
  11.     that ships with Windows NT Setup.
  12.     This sample demonstrates:
  13.       - How to detect installation of your application
  14.       - A typical implementation of QueryVersion, Initialize9x, 
  15.         MigrateUser9x, MigrateSystem9x, InitializeNT, 
  16.         MigrateUserNT and MigraetSystemNT
  17.       - How to provide language-dependent incompatibility
  18.         messages to the user
  19.       - How to remove Setup's incompatibility messages via
  20.         [Handled] section
  21.       - Saving settings to a temporarly file in the working 
  22.         directory
  23.       - Mix use of ANSI and UNICODE
  24.       - Use of the SetupLogError API
  25.       - Deleting files
  26.       - Handling the move from system to system32
  27. Author:
  28.     Jim Schmidt 11-Apr-1997
  29. Revision History:
  30. --*/
  31. #include "pch.h"
  32. //
  33. // Constants
  34. //
  35. #define CP_USASCII          1252
  36. #define END_OF_CODEPAGES    -1
  37. //
  38. // Code page array
  39. //
  40. INT   g_CodePageArray[] = {
  41.             CP_USASCII,
  42.             END_OF_CODEPAGES
  43.             };
  44. //
  45. // Multi-sz (i.e., double-nul terminated) list of files to find
  46. //
  47. CHAR    g_ExeNamesBuf[] = "Blank Screen.scr"
  48.                           "Curves and Colors.scr"
  49.                           "Flying Through Space.scr"
  50.                           "Scrolling Marquee.scr"
  51.                           "Mystify Your Mind.scr";
  52. //
  53. // Copies of the working directory and source directory
  54. //
  55. LPSTR   g_WorkingDirectory = NULL;
  56. LPSTR   g_SourceDirectories = NULL;         // multi-sz
  57. LPSTR   g_SettingsFile = NULL;
  58. LPSTR   g_MigrateDotInf = NULL;
  59. //
  60. // Registry locations and INI file sections
  61. //
  62. #define REGKEY_DESKTOP "Control Panel\Desktop"
  63. #define FULL_REGKEY_DESKTOP "HKR\Control Panel\Desktop"
  64. #define FULL_REGKEY_PWD_PROVIDER "HKLM\System\CurrentControlSet\Control\PwdProvider\SCRSAVE"
  65. #define REGVAL_SCREENSAVEACTIVE "ScreenSaveActive"
  66. #define REGVAL_SCREENSAVELOWPOWERACTIVE "ScreenSaveLowPowerActive"
  67. #define REGVAL_SCREENSAVELOWPOWERTIMEOUT "ScreenSaveLowPowerTimeout"
  68. #define REGVAL_SCREENSAVEPOWEROFFACTIVE "ScreenSavePowerOffActive"
  69. #define REGVAL_SCREENSAVEPOWEROFFTIMEOUT "ScreenSavePowerOffTimeout"
  70. #define REGVAL_SCREENSAVETIMEOUT "ScreenSaveTimeOut"
  71. #define REGVAL_SCREENSAVEUSEPASSWORD "ScreenSaveUsePassword"
  72. #define REGVAL_LOWPOWERACTIVE "LowPowerActive"
  73. #define REGVAL_LOWPOWERTIMEOUT "LowPowerTimeout"
  74. #define REGVAL_POWEROFFACTIVE "PowerOffActive"
  75. #define REGVAL_POWEROFFTIMEOUT "PowerOffTimeout"
  76. #define REGVAL_SCREENSAVERISSECURE "ScreenSaverIsSecure"
  77. //
  78. // State variables
  79. //
  80. BOOL g_FoundPassword = FALSE;
  81. LPCSTR g_User;
  82. CHAR g_UserNameBuf[MAX_PATH];
  83. HANDLE g_hHeap;
  84. BOOL
  85. WINAPI
  86. DllMain (
  87.     IN      HANDLE DllInstance,
  88.     IN      ULONG  ReasonForCall,
  89.     IN      LPVOID Reserved
  90.     )
  91. {
  92.     switch (ReasonForCall)  {
  93.     case DLL_PROCESS_ATTACH:
  94.         //
  95.         // We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
  96.         //
  97.         DisableThreadLibraryCalls (DllInstance);
  98.         //
  99.         // Global init
  100.         //
  101.         g_hHeap = GetProcessHeap();
  102.         if (!MigInf_Initialize()) {
  103.             return FALSE;
  104.         }
  105.         // Open log; FALSE means do not delete existing log
  106.         SetupOpenLog (FALSE);
  107.         break;
  108.     case DLL_PROCESS_DETACH:
  109.         MigInf_CleanUp();
  110.         // Clean up strings
  111.         if (g_WorkingDirectory) {
  112.             HeapFree (g_hHeap, 0, g_WorkingDirectory);
  113.         }
  114.         if (g_SourceDirectories) {
  115.             HeapFree (g_hHeap, 0, g_SourceDirectories);
  116.         }
  117.         if (g_SettingsFile) {
  118.             HeapFree (g_hHeap, 0, g_SettingsFile);
  119.         }
  120.         if (g_MigrateDotInf) {
  121.             HeapFree (g_hHeap, 0, g_MigrateDotInf);
  122.         }
  123.         SetupCloseLog();
  124.         break;
  125.     }
  126.     return TRUE;
  127. }
  128. LONG
  129. CALLBACK
  130. QueryVersion (
  131.     OUT     LPCSTR *ProductID,
  132. OUT     LPUINT DllVersion,
  133. OUT     LPINT *CodePageArray,     OPTIONAL
  134. OUT     LPCSTR *ExeNamesBuf,     OPTIONAL
  135.         LPVOID Reserved
  136.     )
  137. {
  138.     //
  139.     // First, we do some preliminary investigation to see if 
  140.     // our components are installed.  
  141.     //
  142.     if (!GetScrnSaveExe()) {
  143.         //
  144.         // We didn't detect any components, so we return 
  145.         // ERROR_NOT_INSTALLED and the DLL will stop being called.
  146.         // Use this method as much as possible, because user enumeration
  147.         // for MigrateUser9x is relatively slow.  However, don't spend too
  148.         // much time here because QueryVersion is expected to run quickly.
  149.         //
  150.         return ERROR_NOT_INSTALLED;
  151.     }
  152.     //
  153.     // Screen saver is enabled, so tell Setup who we are.  ProductID is used
  154.     // for display, so it must be localized.  The ProductID string is 
  155.     // converted to UNICODE for use on Windows NT via the MultiByteToWideChar
  156.     // Win32 API.  The first element of CodePageArray is used to specify
  157.     // the code page of ProductID, and if no elements are returned in
  158.     // CodePageArray, Setup assumes CP_ACP.
  159.     //
  160.     *ProductID  = g_MyProductId;
  161.     //
  162.     // Report our version.  Zero is reserved for use by DLLs that
  163.     // ship with Windows NT.
  164.     //
  165.     *DllVersion = 1;
  166.     // 
  167.     // Because we have English messages, we return an array that has
  168.     // the English language ID.  The sublanguage is neutral because
  169.     // we do not have currency, time, or other geographic-specific 
  170.     // information in our messages.
  171.     //
  172.     // Tip: If it makes more sense for your DLL to use locales,
  173.     // return ERROR_NOT_INSTALLED if the DLL detects that an appropriate 
  174.     // locale is not installed on the machine.
  175.     //
  176.     *CodePageArray = g_CodePageArray;
  177.     //
  178.     // ExeNamesBuf - we pass a list of file names (the long versions)
  179.     // and let Setup find them for us.  Keep this list short because
  180.     // every instance of the file on every hard drive will be reported
  181.     // in migrate.inf.
  182.     //
  183.     // Most applications don't need this behavior, because the registry
  184.     // usually contains full paths to installed components.  We need it,
  185.     // though, because there are no registry settings that give us the
  186.     // paths of the screen saver DLLs.
  187.     //
  188.     *ExeNamesBuf = g_ExeNamesBuf;
  189.     return ERROR_SUCCESS;
  190. }
  191. LONG
  192. CALLBACK
  193. Initialize9x (
  194. IN      LPCSTR WorkingDirectory,
  195. IN      LPCSTR SourceDirectories,
  196.         LPVOID Reserved
  197.     )
  198. {
  199.     INT Len;
  200.     
  201.     //
  202.     // Because we returned ERROR_SUCCESS in QueryVersion, we are being
  203.     // called for initialization.  Therefore, we know screen savers are
  204.     // enabled on the machine at this point.
  205.     // 
  206.     //
  207.     // Make global copies of WorkingDirectory and SourceDirectories --
  208.     // we will not get this information again, and we shouldn't
  209.     // count on Setup keeping the pointer valid for the life of our
  210.     // DLL.
  211.     //
  212.     Len = CountStringBytes (WorkingDirectory);
  213.     g_WorkingDirectory = HeapAlloc (g_hHeap, 0, Len);
  214.     if (!g_WorkingDirectory) {
  215.         return GetLastError();
  216.     }
  217.     CopyMemory (g_WorkingDirectory, WorkingDirectory, Len);
  218.     Len = CountMultiStringBytes (SourceDirectories);
  219.     g_SourceDirectories = HeapAlloc (g_hHeap, 0, Len);
  220.     if (!g_SourceDirectories) {
  221.         return GetLastError();
  222.     }
  223.     CopyMemory (g_SourceDirectories, SourceDirectories, Len);
  224.     //
  225.     // Now create our private 'settings file' path
  226.     //
  227.     GenerateFilePaths();
  228.     //
  229.     // Return success to have MigrateUser9x called
  230.     //
  231.     // Tip: A DLL can save system settings during Initialize9x as
  232.     //      well as MigrateSystem9x.
  233.     //
  234.     //
  235.     return ERROR_SUCCESS;
  236. }
  237. LONG
  238. CALLBACK 
  239. MigrateUser9x (
  240. IN      HWND ParentWnd, 
  241. IN      LPCSTR UnattendFile,
  242. IN      HKEY UserRegKey, 
  243. IN      LPCSTR UserName, 
  244.         LPVOID Reserved
  245. )
  246. {
  247.     HKEY RegKey;
  248.     LPCSTR ScrnSaveExe;
  249.     DWORD rc = ERROR_SUCCESS;
  250.     LPSTR SectionNameBuf, p;
  251.     DWORD SectionNameSize;
  252.     DWORD Len;
  253.     //
  254.     // This DLL does not require input from the user to upgrade
  255.     // their settings, so ParentWnd is not used.  Avoid displaying
  256.     // any user interface when possible.
  257.     //
  258.     // We don't need to use UnattendFile settings because we are not
  259.     // a service (such as a network redirector).  Therefore, we do not 
  260.     // use the  UnattendFile parameter.
  261.     //
  262.     // We don't have any files that need to be generated or expanded on
  263.     // the NT side of Setup, so we do not write to the 
  264.     // [NT Disk Space Requirements] section of migrate.inf.
  265.     //
  266.     //
  267.     // We must collect a few registry keys:
  268.     //
  269.     //   HKCUControl PanelDesktop
  270.     //        ScreenSaveActive
  271.     //        ScreenSaveLowPowerActive
  272.     //        ScreenSaveLowPowerTimeout
  273.     //        ScreenSavePowerOffActive
  274.     //        ScreenSavePowerOffTimeout
  275.     //        ScreenSaveTimeOut
  276.     //        ScreenSaveUsePassword
  277.     //
  278.     // If ScreenSave_Data exists, we tell the user that their
  279.     // password is not supported by writing an incompatiility
  280.     // message.
  281.     //
  282.     //
  283.     // Save the user name in a global so our utils write to the
  284.     // correct section.
  285.     //
  286.     if (UserName) {
  287.         g_User = UserName;
  288.     } else {
  289.         g_User = S_DEFAULT_USER;
  290.     }
  291.     // OpenRegKey is our utility (in utils.c)
  292.     RegKey = OpenRegKey (UserRegKey, REGKEY_DESKTOP);
  293.     if (!RegKey) {
  294.         //
  295.         // User's registry is invalid, so skip the user
  296.         //
  297.         return ERROR_NOT_INSTALLED;
  298.     }
  299.     //
  300.     // Note: NO changes allowed on Win9x side, we can only read our
  301.     //       settings and save them in a file.
  302.     //
  303.     if (!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEACTIVE) ||
  304.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERACTIVE) ||
  305.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERTIMEOUT) ||
  306.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFACTIVE) ||
  307.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFTIMEOUT) ||
  308.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVETIMEOUT) ||
  309.         !CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEUSEPASSWORD)
  310.         ) {
  311.         rc = GetLastError();
  312.     }
  313.     if (atoi (GetRegValueString (RegKey, REGVAL_SCREENSAVEUSEPASSWORD))) {
  314.         // Queue change so there is only one message
  315.         g_FoundPassword = TRUE;
  316.     }
  317.     //
  318.     // Save EXE location in our dat file
  319.     //
  320.     ScrnSaveExe = GetScrnSaveExe();
  321.     if (ScrnSaveExe) {
  322.         if (!SaveDatFileKeyAndVal (S_SCRNSAVE_EXE, ScrnSaveExe)) {
  323.             rc = GetLastError();
  324.         }
  325.     }
  326.     //
  327.     // Copy control.ini sections to our dat file
  328.     //
  329.     SectionNameSize = 32768;
  330.     SectionNameBuf = (LPSTR) HeapAlloc (g_hHeap, 0, SectionNameSize);
  331.     if (!SectionNameBuf) {
  332.         return GetLastError();
  333.     }
  334.     GetPrivateProfileString (
  335.         NULL,
  336.         NULL,
  337.         S_DOUBLE_EMPTY,
  338.         SectionNameBuf,
  339.         SectionNameSize,
  340.         S_CONTROL_INI
  341.         );
  342.     Len = _mbslen (S_SCRNSAVE_DOT);
  343.     for (p = SectionNameBuf ; *p ; p = _mbschr (p, 0) + 1) {
  344.         //
  345.         // Determine if section name has "Screen Saver." at the beginning
  346.         //
  347.         if (!_mbsnicmp (p, S_SCRNSAVE_DOT, Len)) {
  348.             //
  349.             // It does, so save it to our private file
  350.             //
  351.             SaveControlIniSection (p, p + Len);
  352.         }
  353.     }
  354.     CloseRegKey (RegKey);
  355.     if (rc != ERROR_SUCCESS) {
  356.         CHAR Msg[512];
  357.         wsprintf (Msg, USER_PROCESSING_ERROR, g_User, rc);
  358.         SetupLogError (Msg, LogSevError);
  359.     } else {
  360.         //
  361.         // Write handled for every setting we are processing.  Because this
  362.         // DLL supports only some of the values in the Desktop key, we must
  363.         // be very specific as to which values are actually handled.  If
  364.         // your DLL handles all registry values AND subkeys of a registry
  365.         // key, you can specify NULL in the second parameter of 
  366.         // MigInf_AddHandledRegistry.
  367.         //
  368.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEACTIVE);
  369.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERACTIVE);
  370.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERTIMEOUT);
  371.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFACTIVE);
  372.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFTIMEOUT);
  373.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVETIMEOUT);
  374.         MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEUSEPASSWORD);
  375.     }
  376.     return rc;
  377. }
  378. LONG 
  379. CALLBACK 
  380. MigrateSystem9x (
  381. IN      HWND ParentWnd, 
  382. IN      LPCSTR UnattendFile,
  383.         LPVOID Reserved
  384. )
  385. {
  386.     //
  387.     // We handle the password provider incompatibility
  388.     //
  389.     MigInf_AddHandledRegistry (FULL_REGKEY_PWD_PROVIDER, NULL);
  390.     //
  391.     // Write incompatibility message if necessary (detected in MigrateUser9x)
  392.     //
  393.     if (g_FoundPassword) {
  394.         MigInf_AddMessage (g_MyProductId, PASSWORD_ALERT);
  395.         MigInf_AddMessageRegistry (
  396.                 g_MyProductId, 
  397.                 FULL_REGKEY_DESKTOP, 
  398.                 REGVAL_SCREENSAVEUSEPASSWORD
  399.                 );
  400.     }
  401.     //
  402.     // Write memory version of migrate.inf to disk
  403.     //
  404.     if (!MigInf_WriteInfToDisk()) {
  405.         return GetLastError();
  406.     }
  407.     return ERROR_SUCCESS;
  408. }
  409. LONG
  410. CALLBACK 
  411. InitializeNT (
  412. IN      LPCWSTR WorkingDirectory,
  413. IN      LPCWSTR SourceDirectories,
  414.         LPVOID Reserved
  415. )
  416. {
  417.     INT Length;
  418.     LPCWSTR p;
  419.     //
  420.     // Save our working directory and source directory.  We
  421.     // convert UNICODE to ANSI because we know we are on a US
  422.     // version of NT.  This conversion is not valid for far east
  423.     // languages, because we use CP_ACP (ANSI code page).
  424.     //
  425.     // If your DLL supports far east languages, use UNICODE and
  426.     // call the W version of Win32 functions that take strings.
  427.     //
  428.     //
  429.     // Compute length of source directories
  430.     //
  431.     p = SourceDirectories;
  432.     while (*p) {
  433.         p = wcschr (p, 0) + 1;
  434.     }
  435.     p++;
  436.     Length = (p - SourceDirectories) / sizeof (WCHAR);
  437.     //
  438.     // Convert the directories from UNICODE to DBCS.  This DLL is
  439.     // compiled in ANSI.
  440.     //
  441.     g_WorkingDirectory = (LPSTR) HeapAlloc (g_hHeap, 0, MAX_PATH);
  442.     if (!g_WorkingDirectory) {
  443.         return GetLastError();
  444.     }
  445.     WideCharToMultiByte (
  446.         CP_ACP, 
  447.         0, 
  448.         WorkingDirectory, 
  449.         -1,
  450.         g_WorkingDirectory,
  451.         MAX_PATH,
  452.         NULL,
  453.         NULL
  454.         );
  455.     g_SourceDirectories = (LPSTR) HeapAlloc (g_hHeap, 0, Length * sizeof(WCHAR));
  456.     if (!g_SourceDirectories) {
  457.         return GetLastError();
  458.     }
  459.     WideCharToMultiByte (
  460.         CP_ACP, 
  461.         0, 
  462.         SourceDirectories, 
  463.         Length,
  464.         g_SourceDirectories,
  465.         Length * sizeof (WCHAR),
  466.         NULL,
  467.         NULL
  468.         );
  469.     //
  470.     // Now generate the derived file names
  471.     //
  472.     GenerateFilePaths();
  473.     //
  474.     // Note: We have no use for g_SourceDirectories for the screen saver
  475.     //       upgrade.  The g_SourceDirectories string points to the Windows
  476.     //       NT media (i.e. e:i386) and optional directories specified on
  477.     //       the WINNT32 command line.
  478.     //
  479.     return ERROR_SUCCESS;
  480. }
  481. LONG
  482. CALLBACK 
  483. MigrateUserNT (
  484. IN      HINF UnattendInfHandle,
  485. IN      HKEY UserRegKey,
  486. IN      LPCWSTR UserName,
  487.             LPVOID Reserved
  488. )
  489. {
  490.     HKEY DesktopRegKey;
  491.     DWORD rc = ERROR_SUCCESS;
  492.     BOOL b = TRUE;
  493.     //
  494.     // Setup gives us the UnattendInfHandle instead of the file name,
  495.     // so we don't have to open the inf file repeatitively.  Since
  496.     // Setup opened the handle, let Setup close it.
  497.     //
  498.     //
  499.     // Convert UserName to ANSI
  500.     //
  501.     if (UserName) {
  502.         WideCharToMultiByte (
  503.             CP_ACP, 
  504.             0, 
  505.             UserName, 
  506.             -1,
  507.             g_UserNameBuf,
  508.             MAX_PATH,
  509.             NULL,
  510.             NULL
  511.             );
  512.         g_User = g_UserNameBuf;
  513.     } else {
  514.         g_User = S_DEFAULT_USER;
  515.     }
  516.     //
  517.     // Setup copies all of the Win9x registry, EXCEPT for the registry
  518.     // keys that are suppressed in usermig.inf or wkstamig.inf.
  519.     //
  520.     // We need the HKCUControl PanelDesktop key, and because this is
  521.     // an OS key, the settings have been altered. Most applications
  522.     // store their settings in HKCUSoftware, HKLMSoftware or 
  523.     // HKCCSoftware, and all three of these keys are copied in their
  524.     // entirety (except the operating system settings in 
  525.     // SoftwareMicrosoftWindows).
  526.     //
  527.     // When the non-OS software settings are copied from Win9x to NT, Setup
  528.     // sometimes alters their value.  For example, all registry values
  529.     // that point to a file that was moved from SYSTEM to SYSTEM32
  530.     // are modified to point to the right place.
  531.     //
  532.     //
  533.     // Note: we use CreateRegKey here, but actually the key always exists
  534.     // because the NT defaults have been copied into the user's registry
  535.     // already.  This approach reduces the possibility of failure.
  536.     //
  537.     DesktopRegKey = CreateRegKey (UserRegKey, REGKEY_DESKTOP);
  538.     if (!DesktopRegKey) {
  539.         CHAR Msg[512];
  540.         rc = GetLastError();
  541.         wsprintf (Msg, S_REGISTRY_ERROR, g_User, rc);
  542.         SetupLogError (Msg, LogSevError);
  543.         return rc;
  544.     }
  545.     // The variable b is used to fall through when we fail unexpectedly
  546.     b = TranslateGeneralSetting (
  547.             DesktopRegKey, 
  548.             REGVAL_SCREENSAVEACTIVE, 
  549.             NULL
  550.             );
  551.     if (b) {
  552.         b = TranslateGeneralSetting (
  553.                 DesktopRegKey, 
  554.                 REGVAL_SCREENSAVELOWPOWERACTIVE, 
  555.                 REGVAL_LOWPOWERACTIVE
  556.                 );
  557.     }
  558.     if (b) {
  559.         b = TranslateGeneralSetting (
  560.                 DesktopRegKey, 
  561.                 REGVAL_SCREENSAVELOWPOWERTIMEOUT, 
  562.                 REGVAL_LOWPOWERTIMEOUT
  563.                 );
  564.     }
  565.     if (b) {
  566.         b = TranslateGeneralSetting (
  567.                 DesktopRegKey, 
  568.                 REGVAL_SCREENSAVEPOWEROFFACTIVE, 
  569.                 REGVAL_POWEROFFACTIVE
  570.                 );
  571.     }
  572.     if (b) {
  573.         b = TranslateGeneralSetting (
  574.                 DesktopRegKey, 
  575.                 REGVAL_SCREENSAVEPOWEROFFTIMEOUT, 
  576.                 REGVAL_POWEROFFTIMEOUT
  577.                 );
  578.     }
  579.     if (b) {
  580.         b = TranslateGeneralSetting (
  581.                 DesktopRegKey, 
  582.                 REGVAL_SCREENSAVETIMEOUT, 
  583.                 NULL
  584.                 );
  585.     }
  586.     if (b) {
  587.         b = TranslateGeneralSetting (
  588.                 DesktopRegKey, 
  589.                 REGVAL_SCREENSAVEUSEPASSWORD, 
  590.                 REGVAL_SCREENSAVERISSECURE
  591.                 );
  592.     }
  593.     if (b) {
  594.         b = SaveScrName (DesktopRegKey, S_SCRNSAVE_EXE);
  595.     }
  596.     if (b) {
  597.         //
  598.         // For screen savers work differently on Win9x and NT, perform
  599.         // translation.
  600.         //
  601.         TranslateScreenSavers (UserRegKey);
  602.         
  603.         //
  604.         // The other settings just need to be copied from control.ini
  605.         // to the registry.
  606.         //
  607.         CopyUntranslatedSettings (UserRegKey);
  608.     }
  609.     CloseRegKey (DesktopRegKey);
  610.     //
  611.     // Always return success, because if an error occurred for one user,
  612.     // we don't have a reason not to process the next user.  If your DLL
  613.     // runs into a fatal problem, such as a disk space shortage, you
  614.     // should return the error.
  615.     //
  616.     return ERROR_SUCCESS;
  617. }
  618. LONG
  619. CALLBACK 
  620. MigrateSystemNT (
  621. IN      HINF UnattendInfHandle,
  622.             LPVOID Reserved
  623. )
  624. {
  625.     CHAR FileName[MAX_PATH];
  626.     HINF MigrateInf;
  627.     INFCONTEXT ic;
  628.     CHAR Msg[512];
  629.     //
  630.     // We now delete the Win9x screen savers that were replaced
  631.     // by Windows NT.
  632.     //
  633.     MigrateInf = SetupOpenInfFile (
  634.                         g_MigrateDotInf,
  635.                         NULL,
  636.                         INF_STYLE_WIN4,
  637.                         NULL
  638.                         );
  639.     if (MigrateInf != INVALID_HANDLE_VALUE) {
  640.         //
  641.         // Use Setup APIs to scan migration paths section
  642.         //
  643.         if (SetupFindFirstLine (MigrateInf, S_MIGRATION_PATHS, NULL, &ic)) {
  644.             do {
  645.                 if (SetupGetStringField (&ic, 0, FileName, MAX_PATH, NULL)) {
  646.                     //
  647.                     // All 32-bit binaries located in the Win9x system directory
  648.                     // were moved to system32.  However, the paths reported in
  649.                     // [Migration Paths] are the original Win9x paths.  We
  650.                     // convert c:windowssystemfile to c:windowssystem32file.
  651.                     //
  652.                     ConvertSystemToSystem32 (FileName);
  653.                     //
  654.                     // Now delete the file. Ignore errors because user may have 
  655.                     // lost power, and we may be going through this a second time.
  656.                     //
  657.                     if (!DeleteFile (FileName)) {
  658.                         wsprintf (Msg, DELETEFILE_ERROR, FileName, GetLastError());
  659.                         SetupLogError (Msg, LogSevError);
  660.                     } else {
  661.                         wsprintf (Msg, DELETEFILE_SUCCESS, FileName);
  662.                         SetupLogError (Msg, LogSevInformation);
  663.                     }
  664.                 }
  665.             } while (SetupFindNextLine (&ic, &ic));
  666.         }
  667.     
  668.         SetupCloseInfFile (MigrateInf);
  669.     }
  670.     return ERROR_SUCCESS;
  671. }