Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2324 lines
58 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
migisol.c
Abstract:
Implements an EXE that is used to run migration DLLs in a
separate address space (sandboxing).
Author:
Jim Schmidt (jimschm) 04-Aug-1997
Revision History:
jimschm 19-Mar-2001 Removed DVD check because it is now
in a migration dll
jimschm 02-Jun-1999 Added DVD checking support to avoid
setup crash on a Win9x blue screen
jimschm 18-Mar-1999 Added cleanup for cases where text mode
fails and the user returns to Win9x.
jimschm 23-Sep-1998 Converted to new IPC mechanism
--*/
#include "pch.h"
#include "plugin.h"
#include "migui.h"
#include "ntui.h"
#include "unattend.h"
BOOL g_ReportPhase = FALSE;
BOOL g_MigrationPhase = FALSE;
TCHAR g_DllName[MAX_TCHAR_PATH] = "";
P_INITIALIZE_NT InitializeNT;
P_MIGRATE_USER_NT MigrateUserNT;
P_MIGRATE_SYSTEM_NT MigrateSystemNT;
P_QUERY_VERSION QueryVersion;
P_INITIALIZE_9X Initialize9x;
P_MIGRATE_USER_9X MigrateUser9x;
P_MIGRATE_SYSTEM_9X MigrateSystem9x;
BOOL
WINAPI
MigUtil_Entry (
HINSTANCE hinstDLL,
DWORD fdwReason,
PVOID lpvReserved
);
BOOL
IsNEC98(
VOID
);
#define NO_GUI_ERROR 0
//
// Local functions
//
BOOL
PackExeNames(
PGROWBUFFER GrowBuf,
PCSTR p
);
BOOL
PackDword(
PGROWBUFFER GrowBuf,
DWORD dw
);
BOOL
PackQuadWord(
PGROWBUFFER GrowBuf,
LONGLONG qw
);
BOOL
PackIntArray(
PGROWBUFFER GrowBuf,
PINT Array
);
BOOL
PackString (
PGROWBUFFER GrowBuf,
PCSTR String
);
BOOL
PackBinary (
PGROWBUFFER GrowBuf,
PBYTE Data,
DWORD DataSize
);
HINF
pGetInfHandleFromFileNameW (
PCWSTR UnattendFile
);
VOID
ProcessCommands (
VOID
);
BOOL
pParseCommandLine (
VOID
);
VOID
DoInitializeNT (
PCWSTR Args
);
VOID
DoInitialize9x (
PCSTR Args
);
VOID
DoMigrateUserNT (
PCWSTR Args
);
VOID
DoQueryVersion (
PCSTR Args
);
VOID
DoMigrateUser9x (
PCSTR Args
);
VOID
DoMigrateSystemNT (
PCWSTR Args
);
VOID
DoMigrateSystem9x (
PCSTR Args
);
HWND
pFindParentWindow (
IN PCTSTR WindowTitle,
IN DWORD ProcessId
);
static HINSTANCE g_hLibrary;
HANDLE g_hHeap;
HINSTANCE g_hInst;
#ifdef DEBUG
#define DBG_MIGISOL "MigIsol"
#endif
INT
WINAPI
WinMain (
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR AnsiCmdLine,
INT CmdShow
)
/*++
Routine Description:
The entry point to migisol.exe. The entire body of code is wrapped
in a try/except block to catch all problems with any migration DLLs.
Arguments:
hInstance - The instance handle of this EXE
hPrevInstance - The previous instance handle of this EXE if it is
running, or NULL if no other instances exist.
AnsiCmdLine - The command line (ANSI version)
CmdShow - The ShowWindow command passed by the shell
Return Value:
Returns -1 if an error occurred, or 0 if the exe completed. The exe
will automatically terminate with 0 if the migration DLL throws an
exception.
--*/
{
TCHAR OurDir[MAX_TCHAR_PATH];
PTSTR p;
__try {
g_hInst = hInstance;
g_hHeap = GetProcessHeap();
*OurDir = 0;
GetModuleFileName (NULL, OurDir, ARRAYSIZE(OurDir));
p = _tcsrchr (OurDir, TEXT('\\'));
if (p) {
*p = 0;
if (!_tcschr (OurDir, TEXT('\\'))) {
p[0] = TEXT('\\');
p[1] = 0;
}
SetCurrentDirectory (OurDir);
//
// Force a specific setupapi.dll to be loaded
//
StringCopy (AppendWack (OurDir), TEXT("setupapi.dll"));
LoadLibraryEx (
OurDir,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH
);
}
// Initialize utility library
if (!MigUtil_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL)) {
FreeLibrary (g_hLibrary);
return -1;
}
DEBUGMSG ((DBG_MIGISOL, "migisol.exe started"));
if (!pParseCommandLine()) {
FreeLibrary (g_hLibrary);
return -1;
}
DEBUGMSG ((DBG_MIGISOL, "CmdLine parsed"));
if (!OpenIpc (FALSE, NULL, NULL, NULL)) {
DEBUGMSG ((DBG_MIGISOL, "OpenIpc failed"));
FreeLibrary (g_hLibrary);
return -1;
}
__try {
DEBUGMSG ((DBG_MIGISOL, "Processing commands"));
ProcessCommands();
}
__except (TRUE) {
LOG ((LOG_ERROR, "Upgrade Pack process is terminating because of an exception in WinMain"));
}
CloseIpc();
FreeLibrary (g_hLibrary);
DEBUGMSG ((DBG_MIGISOL, "migisol.exe terminating"));
if (!MigUtil_Entry (g_hInst, DLL_PROCESS_DETACH, NULL)) {
return -1;
}
}
__except (TRUE) {
}
return 0;
}
#define WINNT32_SECTOR_SIZE 512
#define WINNT32_FAT_BOOT_SECTOR_COUNT 1
#define WINNT32_FAT_BOOT_SIZE (WINNT32_SECTOR_SIZE * WINNT32_FAT_BOOT_SECTOR_COUNT)
#define FILE_ATTRIBUTE_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
BOOL
pWriteFATBootSector (
IN PCTSTR BootDataFile,
IN TCHAR BootDriveLetter
)
{
HANDLE BootDataHandle;
BYTE Data[WINNT32_FAT_BOOT_SIZE];
DWORD BytesRead;
BOOL Success = FALSE;
if (GetFileAttributes (BootDataFile) == INVALID_ATTRIBUTES) {
DEBUGMSG ((DBG_ERROR, "Can't find %s", BootDataFile));
return FALSE;
}
BootDataHandle = CreateFile (
BootDataFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (BootDataHandle == INVALID_HANDLE_VALUE) {
DEBUGMSG ((DBG_ERROR, "Can't open %s", BootDataFile));
return FALSE;
}
Success = ReadFile (BootDataHandle, Data, WINNT32_FAT_BOOT_SIZE, &BytesRead, NULL) &&
(BytesRead == WINNT32_FAT_BOOT_SIZE);
CloseHandle (BootDataHandle);
if (Success) {
//
// write the boot sector with this data; don't save NT boot sector
//
Success = WriteDiskSectors (
BootDriveLetter,
0,
WINNT32_FAT_BOOT_SECTOR_COUNT,
WINNT32_SECTOR_SIZE,
Data
);
DEBUGMSG_IF ((
!Success,
DBG_ERROR,
"WriteDiskSectors failed for %c!",
BootDriveLetter
));
}
ELSE_DEBUGMSG ((DBG_ERROR, "Unexpected boot sector size %u in %s", BytesRead, BootDataFile));
return Success;
}
VOID
pCleanUpUndoDirectory (
CHAR BootDrive
)
/*++
Routine Description:
This function delete recursively all files and directories
include and in %windir%\undo directory.
Arguments:
none
Return Value:
none
--*/
{
TCHAR PathBuffer[MAX_PATH];
TCHAR Answer[MAX_PATH];
TCHAR NullPath[] = {0};
DEBUGMSG((DBG_MIGISOL, "Cleanup routine of undo directory"));
if(!BootDrive){
if (!GetWindowsDirectory (PathBuffer, ARRAYSIZE(PathBuffer))) {
DEBUGMSG((DBG_MIGISOL, "GetWindowsDirectory failed"));
return;
}
BootDrive = PathBuffer[0];
}
wsprintf(PathBuffer, TEXT("%c:\\$win_nt$.~bt\\winnt.sif"), BootDrive);
GetPrivateProfileString(
S_WIN9XUPGUSEROPTIONS,
S_PATH_FOR_BACKUP,
NullPath,
Answer,
ARRAYSIZE(Answer),
PathBuffer);
if(!Answer[0]) {
DEBUGMSG ((DBG_MIGISOL, "Failed to retrieve directory path"));
return;
}
wsprintf(PathBuffer, TEXT("%c:\\$win_nt$.~bt\\dataloss"), BootDrive);
if (DoesFileExist (PathBuffer)) {
LOG ((
LOG_INFORMATION,
"Data loss was detected because of a failure to restore one or more files. "
"The data can be recovered from backup files in %s.",
Answer
));
return;
}
SetFileAttributes(Answer, FILE_ATTRIBUTE_NORMAL);
RemoveCompleteDirectory (Answer);
DEBUGMSG ((DBG_MIGISOL, "Cleaned %s directory", Answer));
}
VOID
pCleanUpAfterTextModeFailure (
VOID
)
{
TCHAR squiggleBtDir[] = TEXT("?:\\$win_nt$.~bt");
TCHAR squiggleLsDir[] = TEXT("?:\\$win_nt$.~ls");
TCHAR squiggleBuDir[] = TEXT("?:\\$win_nt$.~bu"); // for NEC98
TCHAR drvLtr[] = TEXT("?:\\$DRVLTR$.~_~");
TCHAR setupLdr[] = TEXT("?:\\$LDR$");
TCHAR txtSetupSif[] = TEXT("?:\\TXTSETUP.SIF");
PCTSTR bootSectDat;
TCHAR setupTempDir[MAX_PATH];
TCHAR bootIni[] = TEXT("?:\\boot.ini");
TCHAR ntLdr[] = TEXT("?:\\NTLDR");
TCHAR ntDetectCom[] = TEXT("?:\\NTDETECT.COM");
TCHAR bootFontBin[] = TEXT("?:\\BOOTFONT.BIN");
TCHAR bootSectDos[] = TEXT("?:\\BootSect.dos");
TCHAR renamedFile1[] = TEXT("?:\\boot~tmp.$$1");
TCHAR renamedFile2[] = TEXT("?:\\boot~tmp.$$2");
TCHAR renamedFile3[] = TEXT("?:\\boot~tmp.$$3");
BOOL noLdr = FALSE;
BOOL noNtDetect = FALSE;
BOOL noBootFontBin = FALSE;
DWORD Drives;
TCHAR DriveLetter;
DWORD Bit;
TCHAR Root[] = TEXT("?:\\");
TCHAR Scratch[MAX_PATH];
PCTSTR bootSectBak;
PCTSTR bootIniBak;
PCTSTR ntldrBak;
PCTSTR bootFontBak;
PCTSTR ntdetectBak;
TCHAR WinDir[MAX_PATH];
DWORD Type;
DWORD Attribs;
FILE_ENUM e;
HANDLE WinInit;
CHAR AnsiBuffer[MAX_PATH + 10];
DWORD Dummy;
PTSTR Write;
BOOL prepareBootIni = FALSE;
CHAR SystemDirPath[MAX_PATH];
TCHAR bootDriveLetter;
PCTSTR bootSectorFile;
BOOL bootLoaderWritten;
HKEY key;
BOOL dontTouchBootCode = FALSE;
if (ISNT()) {
return;
}
DEBUGMSG ((DBG_MIGISOL, "Entering cleanup routine"));
SuppressAllLogPopups (TRUE);
//
// Reinitialize system restore
//
key = OpenRegKeyStr (TEXT("HKLM\\SYSTEM\\CurrentControlSet\\Services\\VxD\\VxDMon"));
if (key) {
RegSetValueEx (key, TEXT("FirstRun"), 0, REG_SZ, (PCBYTE) "Y", 2);
CloseRegKey (key);
}
//
// Prepare windir and temp dir paths, get the bitmask of drive letters
//
// We need to know the system drive to be repaired, since win98 on NEC98
// can boot up from any partition that can be installed.
//
GetSystemDirectory (SystemDirPath, MAX_PATH);
if (!GetWindowsDirectory (setupTempDir, sizeof (setupTempDir) / sizeof (setupTempDir[0]))) {
DEBUGMSG ((DBG_ERROR, "Can't get Windows dir"));
return;
} else {
StringCopy (WinDir, setupTempDir);
}
StringCopy (AppendWack (setupTempDir), TEXT("setup"));
Drives = GetLogicalDrives();
bootDriveLetter = IsNEC98() ? SystemDirPath[0] : TEXT('C');
if (WinDir[0] != bootDriveLetter) {
dontTouchBootCode = TRUE;
}
//
// Create paths
//
bootIniBak = JoinPaths (setupTempDir, S_BOOTINI_BACKUP);
ntldrBak = JoinPaths (setupTempDir, S_NTLDR_BACKUP);
ntdetectBak = JoinPaths (setupTempDir, S_NTDETECT_BACKUP);
bootSectBak = JoinPaths (setupTempDir, S_BOOTSECT_BACKUP);
bootFontBak = JoinPaths (setupTempDir, S_BOOTFONT_BACKUP);
//
// Deltree $win_nt$.~bt and $win_nt$.~ls
//
for (Bit = 1, DriveLetter = TEXT('A') ; Bit ; Bit <<= 1, DriveLetter++) {
if (!(Drives & Bit)) {
continue;
}
Root[0] = DriveLetter;
Type = GetDriveType (Root);
if (Type == DRIVE_FIXED || Type == DRIVE_UNKNOWN) {
//
// Clean this drive
//
squiggleBtDir[0] = DriveLetter;
squiggleLsDir[0] = DriveLetter;
RemoveCompleteDirectory (squiggleBtDir);
RemoveCompleteDirectory (squiggleLsDir);
//
// On NEC98, there may be another temp directry to be clean up.
//
if (IsNEC98()) {
squiggleBuDir[0] = DriveLetter;
RemoveCompleteDirectory (squiggleBuDir);
}
}
}
DEBUGMSG ((DBG_MIGISOL, "Cleaned squiggle dirs"));
//
// Repair boot.ini (do not necessarily restore it to its original form though)
// and clean the root of the drive.
//
for (Bit = 1, DriveLetter = TEXT('A') ; Bit ; Bit <<= 1, DriveLetter++) {
if (!(Drives & Bit)) {
continue;
}
//
// On NEC98, there may be multiple boot files in each partition.
// So we will just take care the system that booted up.
//
if (IsNEC98() && (DriveLetter != SystemDirPath[0])) {
continue;
}
Root[0] = DriveLetter;
Type = GetDriveType (Root);
if (Type == DRIVE_FIXED || Type == DRIVE_UNKNOWN) {
//
// Remove setup from boot.ini if it is on this drive,
// and clean root of the drive.
//
squiggleBtDir[0] = DriveLetter;
squiggleLsDir[0] = DriveLetter;
bootIni[0] = DriveLetter;
drvLtr[0] = DriveLetter;
setupLdr[0] = DriveLetter;
ntLdr[0] = DriveLetter;
ntDetectCom[0] = DriveLetter;
bootFontBin[0] = DriveLetter;
txtSetupSif[0] = DriveLetter;
bootSectDos[0] = DriveLetter;
renamedFile1[0] = DriveLetter;
renamedFile2[0] = DriveLetter;
renamedFile3[0] = DriveLetter;
SetFileAttributes (drvLtr, FILE_ATTRIBUTE_NORMAL);
DeleteFile (drvLtr);
SetFileAttributes (setupLdr, FILE_ATTRIBUTE_NORMAL);
DeleteFile (setupLdr);
SetFileAttributes (txtSetupSif, FILE_ATTRIBUTE_NORMAL);
DeleteFile (txtSetupSif);
//
// If this is the boot drive, and if we have a bootsect.bak and
// boot.bak in the setup temp directory, then that means Win9x had
// an initial boot.ini, and we must restore it. Otherwise there
// was no boot.ini.
//
if (!dontTouchBootCode && DriveLetter == bootDriveLetter) {
DEBUGMSG ((DBG_MIGISOL, "Processing boot drive %c", bootDriveLetter));
//
// test for existence of bootini.bak/bootsect.bak (we don't
// care about the attributes).
//
Attribs = GetFileAttributes (bootIniBak);
DEBUGMSG ((DBG_MIGISOL, "Attributes of %s: 0x%08X", bootIniBak, Attribs));
if (Attribs != INVALID_ATTRIBUTES) {
DEBUGMSG ((DBG_MIGISOL, "Attributes of %s: 0x%08X", bootSectBak, Attribs));
Attribs = GetFileAttributes (bootSectBak);
}
//
// if pair exists, then get attributes of real boot.ini file
//
if (Attribs != INVALID_ATTRIBUTES) {
Attribs = GetFileAttributes (bootIni);
if (Attribs == INVALID_ATTRIBUTES) {
Attribs = FILE_ATTRIBUTE_RHS;
}
//
// Restore ntdetect.com, ntldr, boot sector, and original
// boot.ini.
//
DEBUGMSG ((DBG_MIGISOL, "Restoring dual-boot environment"));
if (pWriteFATBootSector (bootSectBak, bootDriveLetter)) {
SetFileAttributes (bootIni, FILE_ATTRIBUTE_NORMAL);
CopyFile (bootIniBak, bootIni, FALSE); // ignore failure
SetFileAttributes (bootIni, Attribs);
//
// Restore ntldr and ntdetect.com [as a pair]
//
if (DoesFileExist (ntldrBak) && DoesFileExist (ntdetectBak)) {
//
// wipe away collisions with our temp file names,
// then move current working loader to temp files
//
if (DoesFileExist (ntLdr)) {
SetFileAttributes (renamedFile1, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile1);
MoveFile (ntLdr, renamedFile1);
noLdr = FALSE;
} else {
noLdr = TRUE;
}
if (DoesFileExist (ntDetectCom)) {
SetFileAttributes (renamedFile2, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile2);
MoveFile (ntDetectCom, renamedFile2);
noNtDetect = FALSE;
} else {
noNtDetect = TRUE;
}
if (DoesFileExist (bootFontBin)) {
SetFileAttributes (renamedFile3, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile3);
MoveFile (bootFontBin, renamedFile3);
noBootFontBin = FALSE;
} else {
noBootFontBin = TRUE;
}
//
// now attempt to copy backup files to loader location
//
bootLoaderWritten = FALSE;
if (CopyFile (ntldrBak, ntLdr, FALSE)) {
bootLoaderWritten = CopyFile (ntdetectBak, ntDetectCom, FALSE);
DEBUGMSG_IF ((!bootLoaderWritten, DBG_ERROR, "Can't copy %s to %s", ntdetectBak, ntDetectCom));
if (bootLoaderWritten && DoesFileExist (bootFontBak)) {
bootLoaderWritten = CopyFile (bootFontBak, bootFontBin, FALSE);
DEBUGMSG_IF ((!bootLoaderWritten, DBG_ERROR, "Can't copy %s to %s", bootFontBak, bootFontBin));
}
}
ELSE_DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", ntldrBak, ntLdr));
if (bootLoaderWritten) {
//
// success -- remove temp files
//
SetFileAttributes (renamedFile1, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile1);
SetFileAttributes (renamedFile2, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile2);
SetFileAttributes (renamedFile3, FILE_ATTRIBUTE_NORMAL);
DeleteFile (renamedFile3);
} else {
//
// fail -- restore temp files. If restoration
// fails, then generate a working boot.ini.
//
SetFileAttributes (ntLdr, FILE_ATTRIBUTE_NORMAL);
DeleteFile (ntLdr);
SetFileAttributes (ntDetectCom, FILE_ATTRIBUTE_NORMAL);
DeleteFile (ntDetectCom);
SetFileAttributes (bootFontBin, FILE_ATTRIBUTE_NORMAL);
DeleteFile (bootFontBin);
if (!noLdr) {
if (!MoveFile (renamedFile1, ntLdr)) {
prepareBootIni = TRUE;
DEBUGMSG ((DBG_ERROR, "Can't restore %s to %s", renamedFile1, ntLdr));
}
}
if (!noNtDetect) {
if (!MoveFile (renamedFile2, ntDetectCom)) {
prepareBootIni = TRUE;
DEBUGMSG ((DBG_ERROR, "Can't restore %s to %s", renamedFile2, ntDetectCom));
}
}
if (!noBootFontBin) {
if (!MoveFile (renamedFile3, bootFontBin)) {
prepareBootIni = TRUE;
DEBUGMSG ((DBG_ERROR, "Can't restore %s to %s", renamedFile3, bootFontBin));
}
}
}
}
} else {
LOG ((LOG_WARNING, "Unable to restore dual-boot loader"));
}
} else {
//
// Remove the NT boot code. Delete ntdetect.com,
// bootfont.bin and ntldr. If any part of this code fails,
// make a boot.ini that will work. (ntdetect.com won't
// be needed.)
//
SetFileAttributes (ntDetectCom, FILE_ATTRIBUTE_NORMAL);
DeleteFile (ntDetectCom);
Attribs = GetFileAttributes (bootIni);
if (Attribs != INVALID_ATTRIBUTES) {
SetFileAttributes (bootIni, FILE_ATTRIBUTE_NORMAL);
prepareBootIni = TRUE;
//
// SystemDrive is not only C: on NEC98. Also, boot.ini
// should be always sitting on system drive but boot
// drive during setup, if these are separated.
// So we must take care the boot files on system drive.
//
if (GetFileAttributes (bootSectBak) != INVALID_ATTRIBUTES) {
bootSectorFile = bootSectBak;
} else {
bootSectorFile = bootSectDos;
}
if (pWriteFATBootSector (bootSectorFile, bootDriveLetter)) {
DEBUGMSG ((DBG_MIGISOL, "Successfully restored FAT boot sector"));
//
// restored original boot sector, NT boot files not required any longer
//
DeleteFile (bootIni);
SetFileAttributes (ntLdr, FILE_ATTRIBUTE_NORMAL);
DeleteFile (ntLdr);
SetFileAttributes (bootSectDos, FILE_ATTRIBUTE_NORMAL);
DeleteFile (bootSectDos);
SetFileAttributes (ntDetectCom, FILE_ATTRIBUTE_NORMAL);
DeleteFile (ntDetectCom);
SetFileAttributes (bootFontBin, FILE_ATTRIBUTE_NORMAL);
DeleteFile (bootFontBin);
prepareBootIni = FALSE;
} else {
//
// make sure this boot file is not accidentally
// deleted by the end-user
//
SetFileAttributes (ntLdr, FILE_ATTRIBUTE_RHS);
DEBUGMSG ((DBG_ERROR, "Cannot restore FAT boot sector from %s", bootSectDos));
}
}
ELSE_DEBUGMSG ((DBG_MIGISOL, "Skipping removal of boot.ini because it is not present"));
}
//
// If we have any failure, this code here will make a boot
// sector & loader that at least boots Win9x.
//
if (prepareBootIni) {
bootSectDat = JoinPaths (squiggleBtDir, TEXT("BOOTSECT.DAT"));
WritePrivateProfileString (TEXT("Boot Loader"), TEXT("Default"), Root, bootIni);
WritePrivateProfileString (TEXT("Operating Systems"), bootSectDat, NULL, bootIni);
GetPrivateProfileString (TEXT("Operating Systems"), Root, TEXT(""), Scratch, MAX_PATH, bootIni);
if (!Scratch[0]) {
//
// This should never ever occur, but for unknown cases we have this
//
WritePrivateProfileString (TEXT("Operating Systems"), Root, TEXT("Microsoft Windows"), bootIni);
}
WritePrivateProfileString (NULL, NULL, NULL, bootIni);
SetFileAttributes (bootIni, Attribs);
prepareBootIni = FALSE;
FreePathString (bootSectDat);
}
}
}
}
//
// Remove setup's temp dir as best we can. This leaves some junk around,
// but we will fix that on the next reboot.
//
RemoveCompleteDirectory (setupTempDir);
//
// put all remaining files in wininit.ini\[rename] they will be
// automatically removed at next reboot
//
StringCopy (Scratch, WinDir);
StringCopy (AppendWack (Scratch), TEXT("wininit.ini"));
//
// append "manually" since using WritePrivateProfileString will just
// overwrite previous setting
//
if (EnumFirstFile (&e, setupTempDir, NULL)) {
WinInit = CreateFile (
Scratch,
GENERIC_WRITE,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (WinInit != INVALID_HANDLE_VALUE) {
StringCopyA (AnsiBuffer, "\r\n[rename]");
if (WriteFile (WinInit, AnsiBuffer, _mbslen (AnsiBuffer), &Dummy, NULL)) {
StringCopyA (AnsiBuffer, "\r\nNUL=");
Write = GetEndOfString (AnsiBuffer);
do {
#ifdef UNICODE
KnownSizeUnicodeToDbcs (Write, e.FullPath);
#else
StringCopyA (Write, e.FullPath);
#endif
if (!WriteFile (WinInit, AnsiBuffer, _mbslen (AnsiBuffer), &Dummy, NULL)) {
break;
}
} while (EnumNextFile (&e));
}
CloseHandle (WinInit);
}
ELSE_DEBUGMSG ((DBG_MIGISOL, "Cannot create wininit.ini"));
}
ELSE_DEBUGMSG ((DBG_MIGISOL, "No files found in temp dir"));
FreePathString (bootIniBak);
FreePathString (ntldrBak);
FreePathString (ntdetectBak);
FreePathString (bootSectBak);
FreePathString (bootFontBak);
DEBUGMSG ((DBG_MIGISOL, "Leaving cleanup routine"));
}
BOOL
pParseCommandLine (
VOID
)
/*++
Routine Description:
Prepares the global variables g_hLibrary, g_ReportPhase, g_MigrationPhase,
g_DllName and the migration DLL entry points (Initialize9x, etc.)
Arguments:
none
Return Value:
TRUE if the module was successfully loaded, or FALSE if a parsing
error or load error occurred.
--*/
{
PCTSTR CmdLine;
PCTSTR *argv;
INT argc;
INT i;
PCTSTR p;
TCHAR drive;
CmdLine = GetCommandLine();
argv = CommandLineToArgv (CmdLine, &argc);
if (!argv) {
DEBUGMSG ((DBG_MIGISOL, "Parse error"));
return FALSE;
}
//
// Parse command line
//
for (i = 1 ; i < argc ; i++) {
if (argv[i][0] == TEXT('-') || argv[i][0] == TEXT('/')) {
p = _tcsinc (argv[i]);
switch (_totlower (_tcsnextc (p))) {
case 'r':
// Report-phase
g_ReportPhase = TRUE;
break;
case 'm':
// Migration-phase
g_MigrationPhase = TRUE;
break;
case 'b':
drive = '\0';
p = _tcsinc(p);
if(p && ':' == _tcsnextc(p)){
p = _tcsinc(p);
if(p){
drive = (TCHAR)_tcsnextc(p);
}
}
pCleanUpUndoDirectory(drive);
case 'c':
// Restore Win9x
pCleanUpAfterTextModeFailure();
return FALSE;
}
}
else if (!g_DllName[0]) {
StringCopy (g_DllName, argv[i]);
} else {
DEBUGMSG ((DBG_MIGISOL, "Broken arg: %s", argv[i]));
return FALSE;
}
}
//
// Verify expected options exist
//
// One must be FALSE while the other must be TRUE
if (g_ReportPhase == g_MigrationPhase) {
DEBUGMSG ((DBG_MIGISOL, "Too many args"));
return FALSE;
}
if (!g_DllName[0]) {
DEBUGMSG ((DBG_MIGISOL, "No operation"));
return FALSE;
}
//
// Load migration DLL
//
g_hLibrary = LoadLibraryEx (
g_DllName,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH
);
// If it fails, assume the DLL does not want to be loaded
if (!g_hLibrary) {
LOG ((LOG_ERROR, "Cannot load %s, rc=%u", g_DllName, GetLastError()));
return FALSE;
}
// Get proc addresses for NT-side functions
InitializeNT = (P_INITIALIZE_NT) GetProcAddress (g_hLibrary, PLUGIN_INITIALIZE_NT);
MigrateUserNT = (P_MIGRATE_USER_NT) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_USER_NT);
MigrateSystemNT = (P_MIGRATE_SYSTEM_NT) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_SYSTEM_NT);
// Get proc addresses for 9x-side functions
QueryVersion = (P_QUERY_VERSION) GetProcAddress (g_hLibrary, PLUGIN_QUERY_VERSION);
Initialize9x = (P_INITIALIZE_9X) GetProcAddress (g_hLibrary, PLUGIN_INITIALIZE_9X);
MigrateUser9x = (P_MIGRATE_USER_9X) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_USER_9X);
MigrateSystem9x = (P_MIGRATE_SYSTEM_9X) GetProcAddress (g_hLibrary, PLUGIN_MIGRATE_SYSTEM_9X);
// If any function does not exist, ignore the out-of-spec DLL
if (!QueryVersion || !Initialize9x || !MigrateUser9x || !MigrateSystem9x ||
!InitializeNT || !MigrateUserNT || !MigrateSystemNT
) {
LOG ((LOG_ERROR, "Cannot load %s, one or more functions missing", g_DllName));
return FALSE;
}
return TRUE;
}
VOID
ProcessCommands (
VOID
)
/*++
Routine Description:
ProcessCommands waits on the IPC pipe for a command message. When
a command message is received, it is dispatched to the processing
function. If a terminate command is received, the EXE terminates.
If no command is received in one second, the EXE terminates. Therefore,
Setup must always be ready to feed the EXE commands.
Arguments:
none
Return Value:
none
--*/
{
DWORD Command;
PBYTE Data;
DWORD DataSize;
DEBUGMSG ((DBG_MIGISOL, "Starting to process %s", g_DllName));
do {
// We wait for an interval: w95upgnt.dll or w95upg.dll should be ready
// to feed us continuously.
//
// Receive command, don't care about size, OK to fail.
//
if (!GetIpcCommand (
IPC_GET_COMMAND_WIN9X,
&Command,
&Data,
&DataSize
)) {
DEBUGMSG ((DBG_WARNING, "MIGISOL: No command recieved"));
break;
}
DEBUGMSG ((DBG_NAUSEA, "MigIsol - Command recieved: %u", Command));
switch (Command) {
case IPC_QUERY:
if (g_MigrationPhase) {
} else {
DoQueryVersion ((PCSTR) Data);
}
break;
case IPC_INITIALIZE:
if (g_MigrationPhase) {
DoInitializeNT ((PCWSTR) Data);
} else {
DoInitialize9x ((PCSTR) Data);
}
break;
case IPC_MIGRATEUSER:
if (g_MigrationPhase) {
DoMigrateUserNT ((PCWSTR) Data);
} else {
DoMigrateUser9x ((PCSTR) Data);
}
break;
case IPC_MIGRATESYSTEM:
if (g_MigrationPhase) {
DoMigrateSystemNT ((PCWSTR) Data);
} else {
DoMigrateSystem9x ((PCSTR) Data);
}
break;
case IPC_TERMINATE:
DEBUGMSG ((DBG_MIGISOL, "Processing of %s is complete", g_DllName));
return;
default:
DEBUGMSG ((DBG_MIGISOL, "ProcessCommands: Unrecognized command -- terminating"));
return;
}
if (Data) {
MemFree (g_hHeap, 0, Data);
Data = NULL;
}
} while (Command != IPC_TERMINATE);
}
VOID
DoInitializeNT (
PCWSTR Args
)
/*++
Routine Description:
Calls migration DLL's InitializeNT function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the initialize command.
Return Value:
none
--*/
{
PCWSTR WorkingDir = NULL;
PCWSTR SourceDirs = NULL;
PCWSTR EndOfSourceDirs;
PDWORD ReservedSize;
PVOID Reserved;
DWORD rc = RPC_S_CALL_FAILED;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
//
// Set pointers of IN parameters
//
WorkingDir = Args;
SourceDirs = wcschr (Args, 0) + 1;
EndOfSourceDirs = SourceDirs;
while (*EndOfSourceDirs) {
EndOfSourceDirs = wcschr (EndOfSourceDirs, 0);
EndOfSourceDirs++;
}
ReservedSize = (PDWORD) (EndOfSourceDirs + 1);
if (*ReservedSize) {
Reserved = (PVOID) (ReservedSize + 1);
} else {
Reserved = NULL;
}
//
// Set CWD
//
SetCurrentDirectoryW(WorkingDir);
//
// Call migration DLL function
//
__try {
rc = InitializeNT (WorkingDir, SourceDirs, Reserved);
}
__except (TRUE) {
// Send log message
DEBUGMSG ((DBG_MIGISOL, "%s threw an exception in InitializeNT", g_DllName));
rc = ERROR_NOACCESS;
TechnicalLogId = MSG_EXCEPTION_MIGRATE_INIT_NT;
}
//
// No OUT parameters to send
//
SendIpcCommandResults (rc, TechnicalLogId, GuiLogId, NULL, 0);
}
HINF
pGetInfHandleFromFileNameW (
PCWSTR UnattendFile
)
/*++
Routine Description:
pGetInfHandleFromFileName uses the Setup APIs to open the specified
UnattendFile.
Arguments:
UnattendFile - A pointer to the UNICODE file name specifying the unattend
file. This string is converted to ANSI and the ANSI version
of SetupOpenInfFile is called.
Return Value:
The INF handle, or NULL (*not* INVALID_HANDLE_VALUE) if the file could not
be opened.
--*/
{
CHAR AnsiUnattendFile[MAX_MBCHAR_PATH];
HINF UnattendHandle;
KnownSizeWtoA (AnsiUnattendFile, UnattendFile);
UnattendHandle = SetupOpenInfFileA (AnsiUnattendFile, NULL, INF_STYLE_OLDNT|INF_STYLE_WIN4, NULL);
if (UnattendHandle == INVALID_HANDLE_VALUE) {
DEBUGMSG ((DBG_ERROR, "pGetInfHandleFromFileNameW: Could not open %s", UnattendFile));
UnattendHandle = NULL;
}
return UnattendHandle;
}
VOID
DoMigrateUserNT (
PCWSTR Args
)
/*++
Routine Description:
Calls migration DLL's MigrateUserNT function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_MIGRATEUSER command.
Return Value:
none
--*/
{
PCWSTR UnattendFile;
PCWSTR UserRegKey;
PCWSTR UserName;
PCWSTR UserDomain;
PCWSTR FixedUserName;
PCWSTR UserProfileDir;
WCHAR OrgProfileDir[MAX_WCHAR_PATH];
HINF UnattendHandle = NULL;
HKEY UserRegHandle = NULL;
DWORD rc;
PVOID Reserved;
PDWORD ReservedBytesPtr;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
__try {
//
// Preserve USERPROFILE environment variable
//
GetEnvironmentVariableW (S_USERPROFILEW, OrgProfileDir, MAX_WCHAR_PATH);
//
// Set pointers of IN parameters
//
UnattendFile = Args;
UserRegKey = wcschr (UnattendFile, 0) + 1;
UserName = wcschr (UserRegKey, 0) + 1;
UserDomain = wcschr (UserName, 0) + 1;
FixedUserName = wcschr (UserDomain, 0) + 1;
UserProfileDir = wcschr (FixedUserName, 0) + 1;
ReservedBytesPtr = (PDWORD) (wcschr (UserProfileDir, 0) + 1);
if (*ReservedBytesPtr) {
Reserved = (PVOID) (ReservedBytesPtr + 1);
} else {
Reserved = NULL;
}
//
// Set USERPROFILE
//
if (UserProfileDir[0]) {
WCHAR DebugDir[MAX_WCHAR_PATH];
SetEnvironmentVariableW (S_USERPROFILEW, UserProfileDir);
DEBUGMSG ((DBG_MIGISOL, "USERPROFILE set to %ls", UserProfileDir));
GetEnvironmentVariableW (S_USERPROFILEW, DebugDir, MAX_WCHAR_PATH);
DEBUGMSG ((DBG_MIGISOL, "USERPROFILE set to %ls", DebugDir));
}
//
// Get UnattendHandle and UserRegHandle
//
UnattendHandle = pGetInfHandleFromFileNameW (UnattendFile);
UserRegHandle = OpenRegKeyStrW (UserRegKey);
if (!UnattendHandle || !UserRegHandle) {
// Send log message and failure code
rc = ERROR_OPEN_FAILED;
} else {
//
// Call migration DLL function
//
__try {
rc = MigrateUserNT (
UnattendHandle,
UserRegHandle,
UserName[0] ? UserName : NULL,
Reserved
);
}
__except (TRUE) {
// Send log message and failure code
DEBUGMSG ((DBG_MIGISOL, "%s threw an exception in MigrateUserNT", g_DllName));
rc = ERROR_NOACCESS;
TechnicalLogId = MSG_EXCEPTION_MIGRATE_USER_NT;
}
}
//
// No OUT parameters to send
//
if (UserRegHandle) {
CloseRegKey (UserRegHandle);
UserRegHandle = NULL;
}
SendIpcCommandResults (rc, TechnicalLogId, GuiLogId, NULL, 0);
}
__finally {
//
// Clean up
//
SetEnvironmentVariableW (S_USERPROFILEW, OrgProfileDir);
if (UserRegHandle) {
CloseRegKey (UserRegHandle);
}
if (UnattendHandle != INVALID_HANDLE_VALUE) {
SetupCloseInfFile (UnattendHandle);
}
}
}
VOID
DoMigrateSystemNT (
PCWSTR Args
)
/*++
Routine Description:
Calls migration DLL's MigrateSystemNT function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_MIGRATESYSTEM command.
Return Value:
none
--*/
{
PCWSTR UnattendFile;
HINF UnattendHandle = NULL;
DWORD rc;
PVOID Reserved;
PDWORD ReservedBytesPtr;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
__try {
//
// Set pointers of IN parameters
//
UnattendFile = Args;
ReservedBytesPtr = (PDWORD) (wcschr (UnattendFile, 0) + 1);
if (*ReservedBytesPtr) {
Reserved = (PVOID) (ReservedBytesPtr + 1);
} else {
Reserved = NULL;
}
//
// Get UnattendHandle and UserRegHandle
//
UnattendHandle = pGetInfHandleFromFileNameW (UnattendFile);
if (!UnattendHandle) {
rc = ERROR_OPEN_FAILED;
} else {
//
// Call migration DLL function
//
__try {
rc = MigrateSystemNT (UnattendHandle, Reserved);
}
__except (TRUE) {
DEBUGMSG ((DBG_MIGISOL, "%s threw an exception in MigrateSystemNT", g_DllName));
rc = ERROR_NOACCESS;
TechnicalLogId = MSG_EXCEPTION_MIGRATE_SYSTEM_NT;
}
}
//
// No OUT parameters to send
//
SendIpcCommandResults (rc, TechnicalLogId, GuiLogId, NULL, 0);
}
__finally {
if (UnattendHandle != INVALID_HANDLE_VALUE) {
SetupCloseInfFile (UnattendHandle);
}
}
}
VOID
DoQueryVersion (
PCSTR Args
)
/*++
Routine Description:
Calls migration DLL's QueryVersion function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_QUERY command.
Return Value:
none
--*/
{
DWORD rc = RPC_S_CALL_FAILED;
GROWBUFFER GrowBuf = GROWBUF_INIT;
PSTR ProductId = NULL;
UINT DllVersion = 0;
PDWORD CodePageArray = NULL;
PCSTR ExeNames = NULL;
PCSTR WorkingDir;
PVENDORINFO VendorInfo = NULL;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
DEBUGMSG ((DBG_MIGISOL, "Entering DoQueryVersion"));
__try {
//
// Set pointers of IN parameters
//
WorkingDir = (PSTR)Args; // CWD for this process
//
// Change CWD
//
SetCurrentDirectory(WorkingDir);
//
// Call migration DLL function
//
__try {
DEBUGMSG ((DBG_MIGISOL, "QueryVersion: WorkingDir=%s", WorkingDir));
rc = QueryVersion (
&ProductId,
&DllVersion,
&CodePageArray,
&ExeNames,
&VendorInfo
);
DEBUGMSG ((DBG_MIGISOL, "QueryVersion rc=%u", rc));
DEBUGMSG ((DBG_MIGISOL, "VendorInfo=0x%X", VendorInfo));
}
__except (TRUE) {
DEBUGMSG ((
DBG_MIGISOL,
"%s threw an exception in QueryVersion",
g_DllName
));
TechnicalLogId = MSG_MIGDLL_QUERYVERSION_EXCEPTION_LOG;
rc = ERROR_NOACCESS;
}
//
// Unless we know failure occurred, return out parameters
//
if (rc == ERROR_SUCCESS) {
//
// Pack product id string
//
if (!PackString (&GrowBuf, ProductId)) {
DEBUGMSG ((DBG_MIGISOL, "QueryVersion PackProductId failed"));
rc = GetLastError();
__leave;
}
//
// Pack DLL version
//
if (!PackDword(&GrowBuf, DllVersion)) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "QueryVersion DllVersion failed"));
__leave;
}
//
// Pack CP array
//
if (!PackIntArray(&GrowBuf, CodePageArray)) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "QueryVersion PackIntArray failed"));
__leave;
}
//
// Pack Exe Names
//
if (!PackExeNames(&GrowBuf, ExeNames)) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "QueryVersion PackExeNames failed"));
__leave;
}
//
// Pack PVENDORINFO
//
if (!PackDword(&GrowBuf, (DWORD) VendorInfo)) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "QueryVersion VendorInfo failed"));
__leave;
}
if (VendorInfo) {
if (!PackBinary (&GrowBuf, (PBYTE) VendorInfo, sizeof (VENDORINFO))) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "QueryVersion VendorInfo failed"));
__leave;
}
}
}
//
// Send the packed parameters
//
if (!SendIpcCommandResults (
rc,
TechnicalLogId,
GuiLogId,
GrowBuf.End ? GrowBuf.Buf : NULL,
GrowBuf.End
)) {
DEBUGMSG ((
DBG_ERROR,
"DoQueryVersion failed to send command response"
));
LOG ((LOG_ERROR, "Upgrade Pack process could not send reply data"));
}
}
__finally {
FreeGrowBuffer(&GrowBuf);
}
DEBUGMSG ((DBG_MIGISOL, "Leaving DoQueryVersion, rc=%u", rc));
}
VOID
DoInitialize9x (
PCSTR Args
)
/*++
Routine Description:
Calls migration DLL's Initialize9x function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_INITIALIZE command.
Return Value:
none
--*/
{
DWORD rc = RPC_S_CALL_FAILED;
PSTR WorkingDir = NULL;
PSTR SourceDirs = NULL;
PVOID Reserved;
DWORD ReservedSize;
PCSTR p;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
GROWBUFFER GrowBuf = GROWBUF_INIT;
DEBUGMSG ((DBG_MIGISOL, "Entering DoInitialize9x"));
__try {
//
// Set pointers of IN parameters
//
WorkingDir = (PSTR)Args; // CWD for this process
SourceDirs = GetEndOfStringA (WorkingDir) + 1; // arg for Initialize9x
p = SourceDirs;
while (*p) {
p = GetEndOfStringA (p);
p++;
}
p++;
ReservedSize = *((PDWORD) p);
p = (PCSTR) ((PBYTE) p + sizeof (DWORD));
if (ReservedSize) {
Reserved = (PVOID) p;
p = (PCSTR) ((PBYTE) p + ReservedSize);
} else {
Reserved = NULL;
}
//
// Change CWD
//
SetCurrentDirectory(WorkingDir);
//
// Call migration DLL function
//
__try {
rc = Initialize9x (
WorkingDir,
SourceDirs,
Reserved
);
}
__except (TRUE) {
//
// Send log message
//
DEBUGMSG ((DBG_MIGISOL,
"%s threw an exception in Initialize9x",
g_DllName));
TechnicalLogId = MSG_MIGDLL_INITIALIZE9X_EXCEPTION_LOG;
rc = ERROR_NOACCESS;
}
//
// Send reserved
//
if (rc == ERROR_SUCCESS) {
//
// Pack reserved parameter
//
// Set ReservedSize to zero for now because the Reserved arg is an IN only
ReservedSize = 0;
if (!PackBinary (&GrowBuf, (PBYTE) Reserved, ReservedSize)) {
rc = GetLastError();
DEBUGMSG ((DBG_MIGISOL, "Initialize9x reserved failed"));
__leave;
}
}
//
// Send the packed parameters
//
if (!SendIpcCommandResults (
rc,
TechnicalLogId,
GuiLogId,
GrowBuf.End ? GrowBuf.Buf : NULL,
GrowBuf.End
)) {
DEBUGMSG ((
DBG_ERROR,
"DoInitializeNT failed to send command response"
));
LOG ((LOG_ERROR, "Upgrade Pack process could not send reply data"));
}
}
__finally {
FreeGrowBuffer (&GrowBuf);
}
DEBUGMSG ((DBG_MIGISOL, "Leaving DoInitialize9x, rc=%u", rc));
}
VOID
DoMigrateUser9x (
IN PCSTR Args
)
/*++
Routine Description:
Calls migration DLL's MigrateUser9x function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_MIGRATEUSER command.
Return Value:
none
--*/
{
PCSTR ParentWndTitle = NULL;
HWND ParentWnd;
PCSTR UnattendFile = NULL;
PCSTR UserRegKey = NULL;
PCSTR UserName = NULL;
HKEY UserRegHandle = NULL;
DWORD rc = RPC_S_CALL_FAILED;
DWORD ProcessId;
DWORD GuiLogId = 0;
DWORD TechnicalLogId = 0;
DEBUGMSG ((DBG_MIGISOL, "Entering DoMigrateUser9x"));
__try {
//
// Set pointers of IN parameters
//
ParentWndTitle = Args;
UnattendFile = GetEndOfStringA (ParentWndTitle) + 1;
ProcessId = *((PDWORD) UnattendFile);
UnattendFile = (PCSTR) ((PBYTE) UnattendFile + sizeof (DWORD));
UserRegKey = GetEndOfStringA (UnattendFile) + 1;
UserName = GetEndOfStringA (UserRegKey) + 1;
//
// Get UserRegHandle
//
UserRegHandle = OpenRegKeyStr(UserRegKey);
if (!UserRegHandle) {
rc = ERROR_OPEN_FAILED;
} else {
ParentWnd = pFindParentWindow (ParentWndTitle, ProcessId);
//
// Call migration DLL function
//
__try {
rc = MigrateUser9x(
ParentWnd,
UnattendFile,
UserRegHandle,
*UserName ? UserName : NULL,
NULL
);
}
__except (TRUE) {
//
// Send log message
//
DEBUGMSG ((
DBG_MIGISOL,
"%s threw an exception in MigrateUser9x",
g_DllName
));
TechnicalLogId = MSG_MIGDLL_MIGRATEUSER9X_EXCEPTION_LOG;
rc = ERROR_NOACCESS;
}
}
//
// No need to return out parameters
//
if (UserRegHandle) {
CloseRegKey (UserRegHandle);
UserRegHandle = NULL;
}
SendIpcCommandResults (rc, TechnicalLogId, GuiLogId, NULL, 0);
}
__finally {
//
// Free resources
//
if (UserRegHandle) {
CloseRegKey (UserRegHandle);
}
}
DEBUGMSG ((DBG_MIGISOL, "Leaving MigrateUser9x , rc=%u", rc));
}
VOID
DoMigrateSystem9x(
IN PCSTR Args
)
/*++
Routine Description:
Calls migration DLL's MigrateSystem9x function. This function unpacks
the arguments passed by Setup, calls the migration DLL and returns
the status code back to Setup.
Arguments:
Args - A pointer to the argument buffer sent by Setup. This buffer
is received with the IPC_MIGRATESYSTEM command.
Return Value:
none
--*/
{
PCSTR ParentWndTitle = NULL;
DWORD ProcessId;
PCSTR UnattendFile = NULL;
HWND ParentWnd = NULL;
DWORD rc = RPC_S_CALL_FAILED;
DWORD TechnicalLogId = 0;
DWORD GuiLogId = 0;
DEBUGMSG ((DBG_MIGISOL, "Entering DoMigrateSystem9x"));
//
// Set pointers of IN parameters
//
ParentWndTitle = Args;
UnattendFile = GetEndOfStringA (ParentWndTitle) + 1;
ProcessId = *((PDWORD) UnattendFile);
UnattendFile = (PCSTR) ((PBYTE) UnattendFile + sizeof (DWORD));
//
// Get ParentWnd
//
ParentWnd = pFindParentWindow (ParentWndTitle, ProcessId);
//
// Call migration DLL function
//
__try {
rc = MigrateSystem9x(
ParentWnd,
UnattendFile,
NULL
);
}
__except (TRUE) {
//
// Send log message
//
DEBUGMSG ((
DBG_MIGISOL,
"%s threw an exception in MigrateSystem9x",
g_DllName
));
TechnicalLogId = MSG_MIGDLL_MIGRATESYSTEM9X_EXCEPTION_LOG;
rc = ERROR_NOACCESS;
}
//
// No need to return out parameters
//
SendIpcCommandResults (rc, TechnicalLogId, GuiLogId, NULL, 0);
DEBUGMSG ((DBG_MIGISOL, "Leaving DoMigrateSystem9x, rc=%u", rc));
}
//
// Function packs a DWORD into a GrowBuffer.
BOOL
PackDword(
PGROWBUFFER GrowBuf,
DWORD dw
)
{
PVOID p;
p = GrowBuffer (GrowBuf, sizeof(DWORD));
if (!p) {
return FALSE;
}
CopyMemory (p, (PVOID)(&dw), sizeof(dw));
return TRUE;
}
//
// Function packs a LONGLONG into a GrowBuffer
BOOL
PackQuadWord(
PGROWBUFFER GrowBuf,
LONGLONG qw)
{
return (
PackDword(GrowBuf, (DWORD)qw) &&
PackDword(GrowBuf, (DWORD)(qw >> 32)));
}
//
// Function packs 1) a NULL ptr, or 2) array of int terminated by -1, into a
// GrowBuffer.
//
BOOL
PackIntArray(
PGROWBUFFER GrowBuf,
PINT Array
)
{
DWORD Count;
PDWORD ArrayPos;
if (!Array) {
if (!GrowBufAppendDword (GrowBuf, 0)) {
return FALSE;
}
} else {
__try {
Count = 1;
for (ArrayPos = Array ; (*ArrayPos) != -1 ; ArrayPos++) {
Count++;
}
}
__except (TRUE) {
LOG ((LOG_ERROR, "Upgrade Pack %s provided an invalid code page array", g_DllName));
SetLastError (ERROR_NOACCESS);
return FALSE;
}
if (!GrowBufAppendDword (GrowBuf, Count)) {
return FALSE;
}
for (ArrayPos = Array ; Count ; ArrayPos++, Count--) {
if (!GrowBufAppendDword (GrowBuf, (DWORD) (UINT) (*ArrayPos))) {
return FALSE;
}
}
}
return TRUE;
}
//
// Function packs 1) a NULL pointer, or 2) a multi-sz, into a GrowBuffer.
//
BOOL
PackExeNames(
PGROWBUFFER GrowBuf,
PCSTR ExeNames
)
{
PCSTR p;
if (ExeNames) {
__try {
for (p = ExeNames ; *p ; p = GetEndOfStringA (p) + 1) {
}
}
__except (TRUE) {
LOG ((LOG_ERROR, "Upgrade Pack %s provided an invalid file list", g_DllName));
SetLastError (ERROR_NOACCESS);
return FALSE;
}
// Append non-empty strings
for (p = ExeNames ; *p ; p = GetEndOfStringA (p) + 1) {
if (!MultiSzAppendA (GrowBuf, p)) {
return FALSE;
}
}
}
// Append a final empty string
if (!MultiSzAppendA(GrowBuf, "")) {
return FALSE;
}
return TRUE;
}
BOOL
PackString (
PGROWBUFFER GrowBuf,
PCSTR String
)
{
__try {
if (!MultiSzAppendA (GrowBuf, String)) {
return FALSE;
}
}
__except (TRUE) {
DEBUGMSG ((
DBG_ERROR,
"%s provided an invalid ProductID string (%xh)",
g_DllName,
String
));
LOG ((LOG_ERROR, "Upgrade Pack %s provided an invalid product ID", g_DllName));
SetLastError (ERROR_NOACCESS);
return FALSE;
}
return TRUE;
}
BOOL
PackBinary (
PGROWBUFFER GrowBuf,
PBYTE Data,
DWORD DataSize
)
{
PBYTE Buf;
if (!PackDword (GrowBuf, DataSize)) {
return FALSE;
}
if (!DataSize) {
return TRUE;
}
Buf = GrowBuffer (GrowBuf, DataSize);
if (!Buf) {
return FALSE;
}
__try {
CopyMemory (Buf, Data, DataSize);
}
__except (TRUE) {
DEBUGMSG ((
DBG_ERROR,
"%s provided an invalid binary parameter (%xh)",
g_DllName,
Data
));
LOG ((LOG_ERROR, "Upgrade Pack %s provided an invalid binary parameter", g_DllName));
SetLastError (ERROR_NOACCESS);
return FALSE;
}
return TRUE;
}
typedef struct {
PCTSTR WindowTitle;
DWORD ProcessId;
HWND Match;
} FINDWINDOW_STRUCT, *PFINDWINDOW_STRUCT;
BOOL
CALLBACK
pEnumWndProc (
HWND hwnd,
LPARAM lParam
)
/*++
Routine Description:
A callback that is called for every top level window on the system.
It is used with pFindParentWindow to locate a specific window.
Arguments:
hwnd - Specifies the handle of the current enumerated window
lParam - Specifies a pointer to a FINDWINDOW_STRUCT variable that
holds WindowTitle and ProcessId, and receives the
handle if a match is found.
Return Value:
The handle to the matching window, or NULL if no window has the
specified title and process ID.
--*/
{
TCHAR Title[MAX_TCHAR_PATH];
DWORD ProcessId;
PFINDWINDOW_STRUCT p;
p = (PFINDWINDOW_STRUCT) lParam;
GetWindowText (hwnd, Title, MAX_TCHAR_PATH);
GetWindowThreadProcessId (hwnd, &ProcessId);
DEBUGMSG ((DBG_MIGISOL, "Testing window: %s, ID=%x against %s, %x",
Title, ProcessId, p->WindowTitle, p->ProcessId));
if (!StringCompare (Title, p->WindowTitle) &&
ProcessId == p->ProcessId) {
p->Match = hwnd;
LogReInit (&hwnd, NULL);
DEBUGMSG ((DBG_MIGISOL, "Window found: %s, ID=%u", Title, ProcessId));
return FALSE;
}
return TRUE;
}
HWND
pFindParentWindow (
IN PCTSTR WindowTitle,
IN DWORD ProcessId
)
/*++
Routine Description:
Locates the wizard window by enumerating all top-level windows.
The first one to match the supplied title and process ID is used.
Arguments:
WindowTitle - Specifies the name of the window to find.
ProcessId - Specifies the ID of the process who owns the window. If
zero is specified, NULL is returned.
Return Value:
The handle to the matching window, or NULL if no window has the
specified title and process ID.
--*/
{
FINDWINDOW_STRUCT FindWndStruct;
// If no process ID, we cannot have a match
if (!ProcessId) {
return NULL;
}
ZeroMemory (&FindWndStruct, sizeof (FindWndStruct));
FindWndStruct.WindowTitle = WindowTitle;
FindWndStruct.ProcessId = ProcessId;
EnumWindows (pEnumWndProc, (LPARAM) &FindWndStruct);
return FindWndStruct.Match;
}
//
// Check platform that I'm runnig on. Copyed from winnt32[au].dll.
// TRUE - NEC98
// FALSE - others(includes x86)
//
BOOL
IsNEC98(
VOID
)
{
static BOOL Checked = FALSE;
static BOOL Is98;
if(!Checked) {
Is98 = ((GetKeyboardType(0) == 7) && ((GetKeyboardType(1) & 0xff00) == 0x0d00));
Checked = TRUE;
}
return(Is98);
}