|
|
/*++
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); }
|