home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sysmgmt / setup / win9xmig / scrnsave / scrnsave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-13  |  22.0 KB  |  828 lines

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