930 lines
23 KiB
C
930 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
scrnsave.c
|
|
|
|
Abstract:
|
|
|
|
This source file implements the seven required functions for a
|
|
Windows NT 5.0 migration DLL. The DLL demonstrates how the
|
|
interface works by performing the Windows 9x screen saver
|
|
upgrade.
|
|
|
|
The source here is a subset of the actual screen saver DLL
|
|
that ships with Windows NT Setup.
|
|
|
|
This sample demonstrates:
|
|
|
|
- How to detect installation of your application
|
|
|
|
- A typical implementation of QueryVersion, Initialize9x,
|
|
MigrateUser9x, MigrateSystem9x, InitializeNT,
|
|
MigrateUserNT and MigraetSystemNT
|
|
|
|
- How to provide language-dependent incompatibility
|
|
messages to the user
|
|
|
|
- How to remove Setup's incompatibility messages via
|
|
[Handled] section
|
|
|
|
- Saving settings to a temporarly file in the working
|
|
directory
|
|
|
|
- Mix use of ANSI and UNICODE
|
|
|
|
- Use of the SetupLogError API
|
|
|
|
- Deleting files
|
|
|
|
- Handling the move from system to system32
|
|
|
|
Author:
|
|
|
|
Jim Schmidt 11-Apr-1997
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
BOOL
|
|
pLoadFileNames (
|
|
VOID
|
|
);
|
|
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define CP_USASCII 1252
|
|
#define CP_JAPANESE 932
|
|
#define CP_CHT 950
|
|
#define CP_CHS 936
|
|
#define CP_KOREAN 949
|
|
#define END_OF_CODEPAGES -1
|
|
|
|
//
|
|
// Code page array
|
|
//
|
|
|
|
INT g_CodePageArray[] = {
|
|
CP_USASCII,
|
|
CP_JAPANESE,
|
|
CP_CHT,
|
|
CP_CHS,
|
|
CP_KOREAN,
|
|
END_OF_CODEPAGES
|
|
};
|
|
|
|
//
|
|
// Multi-sz (i.e., double-nul terminated) list of files to find
|
|
//
|
|
|
|
CHAR g_ExeNamesBuf[1024];
|
|
CHAR g_MyProductId[MAX_PATH];
|
|
CHAR g_DefaultUser[MAX_PATH];
|
|
|
|
|
|
//
|
|
// Copies of the working directory and source directory
|
|
//
|
|
|
|
LPSTR g_WorkingDirectory = NULL;
|
|
LPSTR g_SourceDirectories = NULL; // multi-sz
|
|
LPSTR g_SettingsFile = NULL;
|
|
LPSTR g_MigrateDotInf = NULL;
|
|
|
|
//
|
|
// Registry locations and INI file sections
|
|
//
|
|
|
|
#define REGKEY_DESKTOP "Control Panel\\Desktop"
|
|
#define FULL_REGKEY_DESKTOP "HKR\\Control Panel\\Desktop"
|
|
#define FULL_REGKEY_PWD_PROVIDER "HKLM\\System\\CurrentControlSet\\Control\\PwdProvider\\SCRSAVE"
|
|
|
|
#define REGVAL_SCREENSAVEACTIVE "ScreenSaveActive"
|
|
#define REGVAL_SCREENSAVELOWPOWERACTIVE "ScreenSaveLowPowerActive"
|
|
#define REGVAL_SCREENSAVELOWPOWERTIMEOUT "ScreenSaveLowPowerTimeout"
|
|
#define REGVAL_SCREENSAVEPOWEROFFACTIVE "ScreenSavePowerOffActive"
|
|
#define REGVAL_SCREENSAVEPOWEROFFTIMEOUT "ScreenSavePowerOffTimeout"
|
|
#define REGVAL_SCREENSAVETIMEOUT "ScreenSaveTimeOut"
|
|
#define REGVAL_SCREENSAVEUSEPASSWORD "ScreenSaveUsePassword"
|
|
|
|
#define REGVAL_LOWPOWERACTIVE "LowPowerActive"
|
|
#define REGVAL_LOWPOWERTIMEOUT "LowPowerTimeout"
|
|
#define REGVAL_POWEROFFACTIVE "PowerOffActive"
|
|
#define REGVAL_POWEROFFTIMEOUT "PowerOffTimeout"
|
|
#define REGVAL_SCREENSAVERISSECURE "ScreenSaverIsSecure"
|
|
|
|
//
|
|
// State variables
|
|
//
|
|
|
|
BOOL g_FoundPassword = FALSE;
|
|
LPCSTR g_User;
|
|
CHAR g_UserNameBuf[MAX_PATH];
|
|
HANDLE g_hHeap;
|
|
HINSTANCE g_hInst;
|
|
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
DllMain (
|
|
IN HANDLE DllInstance,
|
|
IN ULONG ReasonForCall,
|
|
IN LPVOID Reserved
|
|
)
|
|
{
|
|
PCSTR Message;
|
|
|
|
switch (ReasonForCall) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
//
|
|
// We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
|
|
//
|
|
DisableThreadLibraryCalls (DllInstance);
|
|
|
|
//
|
|
// Global init
|
|
//
|
|
g_hInst = DllInstance;
|
|
g_hHeap = GetProcessHeap();
|
|
|
|
if (!MigInf_Initialize()) {
|
|
return FALSE;
|
|
}
|
|
|
|
Message = ParseMessage (MSG_PRODUCT_ID);
|
|
if (Message) {
|
|
_mbscpy (g_MyProductId, Message);
|
|
FreeMessage (Message);
|
|
}
|
|
|
|
Message = ParseMessage (MSG_DEFAULT_USER);
|
|
if (Message) {
|
|
_mbscpy (g_DefaultUser, Message);
|
|
FreeMessage (Message);
|
|
}
|
|
|
|
// Open log; FALSE means do not delete existing log
|
|
SetupOpenLog (FALSE);
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
MigInf_CleanUp();
|
|
|
|
// Clean up strings
|
|
if (g_WorkingDirectory) {
|
|
HeapFree (g_hHeap, 0, g_WorkingDirectory);
|
|
}
|
|
if (g_SourceDirectories) {
|
|
HeapFree (g_hHeap, 0, g_SourceDirectories);
|
|
}
|
|
if (g_SettingsFile) {
|
|
HeapFree (g_hHeap, 0, g_SettingsFile);
|
|
}
|
|
if (g_MigrateDotInf) {
|
|
HeapFree (g_hHeap, 0, g_MigrateDotInf);
|
|
}
|
|
|
|
SetupCloseLog();
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
QueryVersion (
|
|
OUT LPCSTR *ProductID,
|
|
OUT LPUINT DllVersion,
|
|
OUT LPINT *CodePageArray, OPTIONAL
|
|
OUT LPCSTR *ExeNamesBuf, OPTIONAL
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
//
|
|
// Complete load of string resources, act like not installed
|
|
// on resource error (unexpected condition).
|
|
//
|
|
|
|
if (!g_MyProductId[0] || !g_DefaultUser[0]) {
|
|
return ERROR_NOT_INSTALLED;
|
|
}
|
|
|
|
if (!pLoadFileNames()) {
|
|
return ERROR_NOT_INSTALLED;
|
|
}
|
|
|
|
//
|
|
// We do some preliminary investigation to see if
|
|
// our components are installed.
|
|
//
|
|
|
|
if (!GetScrnSaveExe()) {
|
|
//
|
|
// We didn't detect any components, so we return
|
|
// ERROR_NOT_INSTALLED and the DLL will stop being called.
|
|
// Use this method as much as possible, because user enumeration
|
|
// for MigrateUser9x is relatively slow. However, don't spend too
|
|
// much time here because QueryVersion is expected to run quickly.
|
|
//
|
|
return ERROR_NOT_INSTALLED;
|
|
}
|
|
|
|
//
|
|
// Screen saver is enabled, so tell Setup who we are. ProductID is used
|
|
// for display, so it must be localized. The ProductID string is
|
|
// converted to UNICODE for use on Windows NT via the MultiByteToWideChar
|
|
// Win32 API. It uses the same code page as FormatMessage to do
|
|
// its conversion.
|
|
//
|
|
|
|
*ProductID = g_MyProductId;
|
|
|
|
//
|
|
// Report our version. Zero is reserved for use by DLLs that
|
|
// ship with Windows NT.
|
|
//
|
|
|
|
*DllVersion = 1;
|
|
|
|
//
|
|
// We return an array that has all ANSI code pages that we have
|
|
// text for.
|
|
//
|
|
// Tip: If it makes more sense for your DLL to use locales,
|
|
// return ERROR_NOT_INSTALLED if the DLL detects that an appropriate
|
|
// locale is not installed on the machine.
|
|
//
|
|
|
|
*CodePageArray = g_CodePageArray;
|
|
|
|
//
|
|
// ExeNamesBuf - we pass a list of file names (the long versions)
|
|
// and let Setup find them for us. Keep this list short because
|
|
// every instance of the file on every hard drive will be reported
|
|
// in migrate.inf.
|
|
//
|
|
// Most applications don't need this behavior, because the registry
|
|
// usually contains full paths to installed components. We need it,
|
|
// though, because there are no registry settings that give us the
|
|
// paths of the screen saver DLLs.
|
|
//
|
|
|
|
*ExeNamesBuf = g_ExeNamesBuf;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
Initialize9x (
|
|
IN LPCSTR WorkingDirectory,
|
|
IN LPCSTR SourceDirectories,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
INT Len;
|
|
|
|
//
|
|
// Because we returned ERROR_SUCCESS in QueryVersion, we are being
|
|
// called for initialization. Therefore, we know screen savers are
|
|
// enabled on the machine at this point.
|
|
//
|
|
|
|
//
|
|
// Make global copies of WorkingDirectory and SourceDirectories --
|
|
// we will not get this information again, and we shouldn't
|
|
// count on Setup keeping the pointer valid for the life of our
|
|
// DLL.
|
|
//
|
|
|
|
Len = CountStringBytes (WorkingDirectory);
|
|
g_WorkingDirectory = HeapAlloc (g_hHeap, 0, Len);
|
|
|
|
if (!g_WorkingDirectory) {
|
|
return GetLastError();
|
|
}
|
|
|
|
CopyMemory (g_WorkingDirectory, WorkingDirectory, Len);
|
|
|
|
Len = CountMultiStringBytes (SourceDirectories);
|
|
g_SourceDirectories = HeapAlloc (g_hHeap, 0, Len);
|
|
|
|
if (!g_SourceDirectories) {
|
|
return GetLastError();
|
|
}
|
|
|
|
CopyMemory (g_SourceDirectories, SourceDirectories, Len);
|
|
|
|
//
|
|
// Now create our private 'settings file' path
|
|
//
|
|
|
|
GenerateFilePaths();
|
|
|
|
//
|
|
// Return success to have MigrateUser9x called
|
|
//
|
|
// Tip: A DLL can save system settings during Initialize9x as
|
|
// well as MigrateSystem9x.
|
|
//
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateUser9x (
|
|
IN HWND ParentWnd,
|
|
IN LPCSTR UnattendFile,
|
|
IN HKEY UserRegKey,
|
|
IN LPCSTR UserName,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
HKEY RegKey;
|
|
LPCSTR ScrnSaveExe;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
LPSTR SectionNameBuf, p;
|
|
DWORD SectionNameSize;
|
|
DWORD Len;
|
|
|
|
//
|
|
// This DLL does not require input from the user to upgrade
|
|
// their settings, so ParentWnd is not used. Avoid displaying
|
|
// any user interface when possible.
|
|
//
|
|
// We don't need to use UnattendFile settings because we are not
|
|
// a service (such as a network redirector). Therefore, we do not
|
|
// use the UnattendFile parameter.
|
|
//
|
|
// We don't have any files that need to be generated or expanded on
|
|
// the NT side of Setup, so we do not write to the
|
|
// [NT Disk Space Requirements] section of migrate.inf.
|
|
//
|
|
|
|
//
|
|
// We must collect a few registry keys:
|
|
//
|
|
// HKCU\Control Panel\Desktop
|
|
// ScreenSaveActive
|
|
// ScreenSaveLowPowerActive
|
|
// ScreenSaveLowPowerTimeout
|
|
// ScreenSavePowerOffActive
|
|
// ScreenSavePowerOffTimeout
|
|
// ScreenSaveTimeOut
|
|
// ScreenSaveUsePassword
|
|
//
|
|
// If ScreenSave_Data exists, we tell the user that their
|
|
// password is not supported by writing an incompatiility
|
|
// message.
|
|
//
|
|
|
|
//
|
|
// Save the user name in a global so our utils write to the
|
|
// correct section.
|
|
//
|
|
|
|
if (UserName) {
|
|
g_User = UserName;
|
|
} else {
|
|
g_User = g_DefaultUser;
|
|
}
|
|
|
|
// OpenRegKey is our utility (in utils.c)
|
|
RegKey = OpenRegKey (UserRegKey, REGKEY_DESKTOP);
|
|
if (!RegKey) {
|
|
//
|
|
// User's registry is invalid, so skip the user
|
|
//
|
|
return ERROR_NOT_INSTALLED;
|
|
}
|
|
|
|
//
|
|
// Note: NO changes allowed on Win9x side, we can only read our
|
|
// settings and save them in a file.
|
|
//
|
|
|
|
if (!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEACTIVE) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERACTIVE) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVELOWPOWERTIMEOUT) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFACTIVE) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEPOWEROFFTIMEOUT) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVETIMEOUT) ||
|
|
!CopyRegValueToDatFile (RegKey, REGVAL_SCREENSAVEUSEPASSWORD)
|
|
) {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
if (atoi (GetRegValueString (RegKey, REGVAL_SCREENSAVEUSEPASSWORD))) {
|
|
// Queue change so there is only one message
|
|
g_FoundPassword = TRUE;
|
|
}
|
|
|
|
//
|
|
// Save EXE location in our dat file
|
|
//
|
|
|
|
ScrnSaveExe = GetScrnSaveExe();
|
|
|
|
if (ScrnSaveExe) {
|
|
if (!SaveDatFileKeyAndVal (S_SCRNSAVE_EXE, ScrnSaveExe)) {
|
|
rc = GetLastError();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy control.ini sections to our dat file
|
|
//
|
|
|
|
SectionNameSize = 32768;
|
|
SectionNameBuf = (LPSTR) HeapAlloc (g_hHeap, 0, SectionNameSize);
|
|
if (!SectionNameBuf) {
|
|
return GetLastError();
|
|
}
|
|
|
|
GetPrivateProfileString (
|
|
NULL,
|
|
NULL,
|
|
S_DOUBLE_EMPTY,
|
|
SectionNameBuf,
|
|
SectionNameSize,
|
|
S_CONTROL_INI
|
|
);
|
|
|
|
Len = _mbslen (S_SCRNSAVE_DOT);
|
|
for (p = SectionNameBuf ; *p ; p = _mbschr (p, 0) + 1) {
|
|
//
|
|
// Determine if section name has "Screen Saver." at the beginning
|
|
//
|
|
|
|
if (!_mbsnicmp (p, S_SCRNSAVE_DOT, Len)) {
|
|
//
|
|
// It does, so save it to our private file
|
|
//
|
|
SaveControlIniSection (p, p + Len);
|
|
}
|
|
}
|
|
|
|
CloseRegKey (RegKey);
|
|
|
|
if (rc != ERROR_SUCCESS) {
|
|
LOG ((LOG_ERROR, MSG_PROCESSING_ERROR, g_User, rc));
|
|
} else {
|
|
//
|
|
// Write handled for every setting we are processing. Because this
|
|
// DLL supports only some of the values in the Desktop key, we must
|
|
// be very specific as to which values are actually handled. If
|
|
// your DLL handles all registry values AND subkeys of a registry
|
|
// key, you can specify NULL in the second parameter of
|
|
// MigInf_AddHandledRegistry.
|
|
//
|
|
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEACTIVE);
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERACTIVE);
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVELOWPOWERTIMEOUT);
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFACTIVE);
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEPOWEROFFTIMEOUT);
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVETIMEOUT);
|
|
|
|
//
|
|
// We do not say that we handle REGVAL_SCREENSAVEUSEPASSWORD when we write
|
|
// an incompatibility message for it. If we did, we would be suppressing
|
|
// our own message!
|
|
//
|
|
|
|
if (!g_FoundPassword) {
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_DESKTOP, REGVAL_SCREENSAVEUSEPASSWORD);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateSystem9x (
|
|
IN HWND ParentWnd,
|
|
IN LPCSTR UnattendFile,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
HINF MigrateInf;
|
|
INFCONTEXT ic;
|
|
CHAR FileName[MAX_PATH*2];
|
|
PCSTR Message;
|
|
|
|
//
|
|
// We handle the password provider incompatibility
|
|
//
|
|
|
|
MigInf_AddHandledRegistry (FULL_REGKEY_PWD_PROVIDER, NULL);
|
|
|
|
//
|
|
// Write incompatibility message if necessary (detected in MigrateUser9x)
|
|
//
|
|
|
|
if (g_FoundPassword) {
|
|
Message = ParseMessage (MSG_PASSWORD_ALERT);
|
|
MigInf_AddMessage (g_MyProductId, Message);
|
|
FreeMessage (Message);
|
|
|
|
MigInf_AddMessageRegistry (
|
|
g_MyProductId,
|
|
FULL_REGKEY_DESKTOP,
|
|
REGVAL_SCREENSAVEUSEPASSWORD
|
|
);
|
|
}
|
|
|
|
//
|
|
// Use Setup APIs to scan migration paths section
|
|
//
|
|
|
|
MigrateInf = SetupOpenInfFile (
|
|
g_MigrateDotInf,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL
|
|
);
|
|
|
|
if (MigrateInf != INVALID_HANDLE_VALUE) {
|
|
if (SetupFindFirstLine (MigrateInf, S_MIGRATION_PATHS, NULL, &ic)) {
|
|
do {
|
|
if (SetupGetStringField (&ic, 0, FileName, MAX_PATH, NULL)) {
|
|
//
|
|
// We will be deleting the file, so we must notify Setup
|
|
// by writing an entry to [Moved] that has an empty right
|
|
// side.
|
|
//
|
|
|
|
MigInf_AddMovedFile (FileName, "");
|
|
}
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
}
|
|
|
|
SetupCloseInfFile (MigrateInf);
|
|
} else {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Write memory version of migrate.inf to disk
|
|
//
|
|
|
|
if (!MigInf_WriteInfToDisk()) {
|
|
return GetLastError();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
InitializeNT (
|
|
IN LPCWSTR WorkingDirectory,
|
|
IN LPCWSTR SourceDirectories,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
INT Length;
|
|
LPCWSTR p;
|
|
|
|
//
|
|
// Save our working directory and source directory. We
|
|
// convert UNICODE to ANSI, and we use the system code page.
|
|
//
|
|
|
|
//GetSystemCodePage
|
|
|
|
//
|
|
// Compute length of source directories
|
|
//
|
|
|
|
p = SourceDirectories;
|
|
while (*p) {
|
|
p = wcschr (p, 0) + 1;
|
|
}
|
|
p++;
|
|
Length = (p - SourceDirectories) / sizeof (WCHAR);
|
|
|
|
//
|
|
// Convert the directories from UNICODE to DBCS. This DLL is
|
|
// compiled in ANSI.
|
|
//
|
|
|
|
g_WorkingDirectory = (LPSTR) HeapAlloc (g_hHeap, 0, MAX_PATH);
|
|
if (!g_WorkingDirectory) {
|
|
return GetLastError();
|
|
}
|
|
|
|
WideCharToMultiByte (
|
|
CP_ACP,
|
|
0,
|
|
WorkingDirectory,
|
|
-1,
|
|
g_WorkingDirectory,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
g_SourceDirectories = (LPSTR) HeapAlloc (g_hHeap, 0, Length * sizeof(WCHAR));
|
|
if (!g_SourceDirectories) {
|
|
return GetLastError();
|
|
}
|
|
|
|
WideCharToMultiByte (
|
|
CP_ACP,
|
|
0,
|
|
SourceDirectories,
|
|
Length,
|
|
g_SourceDirectories,
|
|
Length * sizeof (WCHAR),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Now generate the derived file names
|
|
//
|
|
|
|
GenerateFilePaths();
|
|
|
|
//
|
|
// Note: We have no use for g_SourceDirectories for the screen saver
|
|
// upgrade. The g_SourceDirectories string points to the Windows
|
|
// NT media (i.e. e:\i386) and optional directories specified on
|
|
// the WINNT32 command line.
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateUserNT (
|
|
IN HINF UnattendInfHandle,
|
|
IN HKEY UserRegKey,
|
|
IN LPCWSTR UserName,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
HKEY DesktopRegKey;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
BOOL b = TRUE;
|
|
|
|
//
|
|
// Setup gives us the UnattendInfHandle instead of the file name,
|
|
// so we don't have to open the inf file repeatitively. Since
|
|
// Setup opened the handle, let Setup close it.
|
|
//
|
|
|
|
//
|
|
// Convert UserName to ANSI
|
|
//
|
|
|
|
if (UserName) {
|
|
WideCharToMultiByte (
|
|
CP_ACP,
|
|
0,
|
|
UserName,
|
|
-1,
|
|
g_UserNameBuf,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
g_User = g_UserNameBuf;
|
|
} else {
|
|
g_User = g_DefaultUser;
|
|
}
|
|
|
|
//
|
|
// Setup copies all of the Win9x registry, EXCEPT for the registry
|
|
// keys that are suppressed in usermig.inf or wkstamig.inf.
|
|
//
|
|
// We need the HKCU\Control Panel\Desktop key, and because this is
|
|
// an OS key, the settings have been altered. Most applications
|
|
// store their settings in HKCU\Software, HKLM\Software or
|
|
// HKCC\Software, and all three of these keys are copied in their
|
|
// entirety (except the operating system settings in
|
|
// Software\Microsoft\Windows).
|
|
//
|
|
// When the non-OS software settings are copied from Win9x to NT, Setup
|
|
// sometimes alters their value. For example, all registry values
|
|
// that point to a file that was moved from SYSTEM to SYSTEM32
|
|
// are modified to point to the right place.
|
|
//
|
|
|
|
//
|
|
// Note: we use CreateRegKey here, but actually the key always exists
|
|
// because the NT defaults have been copied into the user's registry
|
|
// already. This approach reduces the possibility of failure.
|
|
//
|
|
|
|
DesktopRegKey = CreateRegKey (UserRegKey, REGKEY_DESKTOP);
|
|
if (!DesktopRegKey) {
|
|
rc = GetLastError();
|
|
LOG ((LOG_ERROR, MSG_REGISTRY_ERROR, g_User, rc));
|
|
|
|
return rc;
|
|
}
|
|
|
|
// The variable b is used to fall through when we fail unexpectedly
|
|
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVEACTIVE,
|
|
NULL
|
|
);
|
|
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVELOWPOWERACTIVE,
|
|
REGVAL_LOWPOWERACTIVE
|
|
);
|
|
}
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVELOWPOWERTIMEOUT,
|
|
REGVAL_LOWPOWERTIMEOUT
|
|
);
|
|
}
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVEPOWEROFFACTIVE,
|
|
REGVAL_POWEROFFACTIVE
|
|
);
|
|
}
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVEPOWEROFFTIMEOUT,
|
|
REGVAL_POWEROFFTIMEOUT
|
|
);
|
|
}
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVETIMEOUT,
|
|
NULL
|
|
);
|
|
}
|
|
if (b) {
|
|
b = TranslateGeneralSetting (
|
|
DesktopRegKey,
|
|
REGVAL_SCREENSAVEUSEPASSWORD,
|
|
REGVAL_SCREENSAVERISSECURE
|
|
);
|
|
}
|
|
|
|
if (b) {
|
|
b = SaveScrName (DesktopRegKey, S_SCRNSAVE_EXE);
|
|
}
|
|
|
|
if (b) {
|
|
//
|
|
// For screen savers work differently on Win9x and NT, perform
|
|
// translation.
|
|
//
|
|
|
|
TranslateScreenSavers (UserRegKey);
|
|
|
|
//
|
|
// The other settings just need to be copied from control.ini
|
|
// to the registry.
|
|
//
|
|
|
|
CopyUntranslatedSettings (UserRegKey);
|
|
}
|
|
|
|
|
|
CloseRegKey (DesktopRegKey);
|
|
|
|
//
|
|
// Always return success, because if an error occurred for one user,
|
|
// we don't have a reason not to process the next user. If your DLL
|
|
// runs into a fatal problem, such as a disk space shortage, you
|
|
// should return the error.
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateSystemNT (
|
|
IN HINF UnattendInfHandle,
|
|
LPVOID Reserved
|
|
)
|
|
{
|
|
CHAR FileName[MAX_PATH];
|
|
HINF MigrateInf;
|
|
INFCONTEXT ic;
|
|
|
|
//
|
|
// We now delete the Win9x screen savers that were replaced
|
|
// by Windows NT.
|
|
//
|
|
|
|
MigrateInf = SetupOpenInfFile (
|
|
g_MigrateDotInf,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL
|
|
);
|
|
|
|
if (MigrateInf != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Use Setup APIs to scan migration paths section
|
|
//
|
|
|
|
if (SetupFindFirstLine (MigrateInf, S_MIGRATION_PATHS, NULL, &ic)) {
|
|
do {
|
|
if (SetupGetStringField (&ic, 0, FileName, MAX_PATH, NULL)) {
|
|
//
|
|
// All 32-bit binaries located in the Win9x system directory
|
|
// were moved to system32. However, since we listed the
|
|
// screen savers in [Migration Paths], the screen savers were
|
|
// not moved.
|
|
//
|
|
// Now delete the file. Ignore errors because user may have
|
|
// lost power, and we may be going through this a second time.
|
|
//
|
|
|
|
if (!DeleteFile (FileName)) {
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
LOG ((LOG_ERROR, MSG_DELETEFILE_ERROR));
|
|
}
|
|
} else {
|
|
LOG ((LOG_INFORMATION, MSG_DELETEFILE_SUCCESS, FileName));
|
|
}
|
|
}
|
|
} while (SetupFindNextLine (&ic, &ic));
|
|
}
|
|
|
|
SetupCloseInfFile (MigrateInf);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pLoadFileNames (
|
|
VOID
|
|
)
|
|
{
|
|
PSTR p;
|
|
PCSTR Message;
|
|
|
|
Message = ParseMessage (MSG_FILENAMES);
|
|
_mbscpy (g_ExeNamesBuf, Message);
|
|
FreeMessage (Message);
|
|
|
|
if (!g_ExeNamesBuf[0]) {
|
|
return FALSE;
|
|
}
|
|
|
|
p = g_ExeNamesBuf;
|
|
|
|
while (*p) {
|
|
if (_mbsnextc (p) == '|') {
|
|
*p = 0;
|
|
}
|
|
|
|
p = _mbsinc (p);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|