|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
caller.c
Abstract:
Calls the entry points for a specific DLL.
Author:
Jim Schmidt (jimschm) 14-Jan-1998
Revision History:
jimschm 23-Sep-1998 Updated for new IPC mechanism
--*/
#include "pch.h"
#include "plugin.h"
#include "migdllp.h"
#define DBG_MIGDLLS "MigDLLs"
//
// Globals
//
PBYTE g_Data; DWORD g_DataSize; BOOL g_UseMigIsol = TRUE;
TCHAR g_OldDirectory[MAX_TCHAR_PATH]; HINSTANCE g_MigDllLib; P_QUERY_VERSION TestQueryVersion; P_INITIALIZE_9X TestInitialize9x; P_MIGRATE_USER_9X TestMigrateUser9x; P_MIGRATE_SYSTEM_9X TestMigrateSystem9x; P_INITIALIZE_NT TestInitializeNT; P_MIGRATE_USER_NT TestMigrateUserNT; P_MIGRATE_SYSTEM_NT TestMigrateSystemNT; PCSTR g_DllName; CHAR g_DllPath[MAX_MBCHAR_PATH];
//
// Local prototypes
//
VOID pFreeGlobalIpcBuffer ( VOID );
DWORD pFinishHandshake9x( VOID );
//
// Implementation
//
BOOL OpenMigrationDll ( IN PCSTR MigrationDllPath, IN PCSTR WorkingDir ) { CHAR MigIsolPath[MAX_MBCHAR_PATH]; PCSTR TempDir;
StringCopyA (g_DllPath, MigrationDllPath); if (!g_DllName) { g_DllName = g_DllPath; }
GetCurrentDirectory (MAX_TCHAR_PATH, g_OldDirectory);
if (!g_UseMigIsol) {
//
// Load the library and verify that all required functions exist
//
g_MigDllLib = LoadLibrary (MigrationDllPath); if (!g_MigDllLib) { return FALSE; }
TestQueryVersion = (P_QUERY_VERSION) GetProcAddress (g_MigDllLib, PLUGIN_QUERY_VERSION); TestInitialize9x = (P_INITIALIZE_9X) GetProcAddress (g_MigDllLib, PLUGIN_INITIALIZE_9X); TestMigrateUser9x = (P_MIGRATE_USER_9X) GetProcAddress (g_MigDllLib, PLUGIN_MIGRATE_USER_9X); TestMigrateSystem9x = (P_MIGRATE_SYSTEM_9X) GetProcAddress (g_MigDllLib, PLUGIN_MIGRATE_SYSTEM_9X); TestInitializeNT = (P_INITIALIZE_NT) GetProcAddress (g_MigDllLib, PLUGIN_INITIALIZE_NT); TestMigrateUserNT = (P_MIGRATE_USER_NT) GetProcAddress (g_MigDllLib, PLUGIN_MIGRATE_USER_NT); TestMigrateSystemNT = (P_MIGRATE_SYSTEM_NT) GetProcAddress (g_MigDllLib, PLUGIN_MIGRATE_SYSTEM_NT);
if (!TestQueryVersion || !TestInitialize9x || !TestMigrateUser9x || !TestMigrateSystem9x || !TestInitializeNT || !TestMigrateUserNT || !TestMigrateSystemNT ) { FreeLibrary (g_MigDllLib); g_MigDllLib = NULL; return FALSE; }
} else { //
// Generate path to migisol.exe, installed by the copy thread in UI
//
TempDir = ConvertAtoT (g_TempDir); MYASSERT (TempDir); wsprintfA (MigIsolPath, "%s\\%s", TempDir, S_MIGISOL_EXE); FreeAtoT (TempDir);
if (!OpenIpc ( TRUE, // TRUE: Win95 side
MigIsolPath, MigrationDllPath, WorkingDir )) {
LOG (( LOG_WARNING, "Can't establish IPC connection for %s", MigrationDllPath ));
return FALSE; } }
return TRUE; }
VOID CloseMigrationDll ( VOID ) { if (!g_UseMigIsol) { if (g_MigDllLib) { FreeLibrary (g_MigDllLib); g_MigDllLib = NULL; }
SetCurrentDirectory (g_OldDirectory);
} else { CloseIpc(); }
pFreeGlobalIpcBuffer(); }
BOOL pValidateBinary ( IN PBYTE Data, IN UINT Size ) { BYTE Remember;
if (!Data || !Size) { return TRUE; }
__try { Remember = Data[0]; Data[0] = Remember; Remember = Data[Size - 1]; Data[Size - 1] = Remember; } __except (TRUE) { DEBUGMSG ((DBG_MIGDLLS, "pValidateBinary failed for %u bytes", Size)); return FALSE; }
return TRUE; }
BOOL pValidateNonNullString ( IN PCSTR String ) { __try { SizeOfStringA (String); if (*String == 0) { DEBUGMSG ((DBG_MIGDLLS, "pValidateNonNullString found zero-length string")); return FALSE; } } __except (TRUE) { DEBUGMSG ((DBG_MIGDLLS, "pValidateNonNullString failed")); return FALSE; }
return TRUE; }
BOOL pValidateIntArray ( IN PINT Array ) { PINT End;
if (!Array) { return TRUE; }
__try { End = Array; while (*End != -1) { End++; } } __except (TRUE) { DEBUGMSG ((DBG_MIGDLLS, "Int Array is invalid (or not terminated with -1)")); return FALSE; }
return TRUE; }
BOOL pValidateMultiString ( IN PCSTR Strings ) { if (!Strings) { return TRUE; }
__try { while (*Strings) { Strings = GetEndOfStringA (Strings) + 1; } } __except (TRUE) { DEBUGMSG ((DBG_MIGDLLS, "pValidateMultiString failed")); return FALSE; }
return TRUE; }
DWORD pRemoteQueryVersion( OUT PCSTR *ProductId, OUT PUINT DllVersion, OUT PDWORD *CodePageArray, OUT PCSTR *ExeNamesBuf, IN PCSTR WorkingDir, OUT PVENDORINFO *VendorInfo ) { PBYTE DataPtr; INT ReturnArraySize; PDWORD ReturnArray; DWORD rc = ERROR_SUCCESS; GROWBUFFER GrowBuf = GROWBUF_INIT; PCTSTR p; DWORD DataSize;
//
// Free any previous data... but do not free before we return, because the
// new data buffer will be used directly by the caller. (The caller will
// make copies of all the settings.)
//
pFreeGlobalIpcBuffer();
__try {
//
// Send the working directory, since migisol will need to set this before
// calling QueryVersion.
//
MultiSzAppendA (&GrowBuf, WorkingDir);
DEBUGMSG ((DBG_MIGDLLS, "Calling QueryVersion via migisol.exe"));
if (!SendIpcCommand ( IPC_QUERY, GrowBuf.Buf, GrowBuf.End )) {
LOG ((LOG_ERROR,"pRemoteQueryVersion failed to send command")); rc = GetLastError(); __leave; }
//
// Finish transaction. Caller will interpret return code.
//
DEBUGMSG ((DBG_MIGDLLS, "Getting results from migisol.exe"));
rc = pFinishHandshake9x();
//
// Unpack the buffer, if received.
//
if (g_Data) {
DEBUGMSG ((DBG_MIGDLLS, "Parsing QueryVersion return data"));
__try { DataPtr = g_Data;
//
// Unpack product ID
//
*ProductId = DataPtr; DataPtr = GetEndOfStringA ((PCSTR) DataPtr) + 1;
//
// Unpack DLL version
//
*DllVersion = *((PINT) DataPtr); DataPtr += sizeof(INT);
//
// Unpack the CP array
//
ReturnArraySize = *((PINT) DataPtr); DataPtr += sizeof(INT);
if (ReturnArraySize) { ReturnArray = (PDWORD) DataPtr; DataPtr += ReturnArraySize * sizeof (DWORD); } else { ReturnArray = NULL; }
*CodePageArray = ReturnArray;
//
// Unpack Exe name buffer
//
*ExeNamesBuf = (PCSTR) DataPtr;
p = *ExeNamesBuf; while (*p) { p = GetEndOfStringA (p) + 1; } DataPtr = (PBYTE) (p + 1);
*VendorInfo = *((PVENDORINFO *) DataPtr); DataPtr += sizeof (PVENDORINFO);
DEBUGMSG ((DBG_MIGDLLS, "Unpacked VendorInfo pointer is 0x%X", *VendorInfo));
if (*VendorInfo) { DataSize = *((PDWORD) DataPtr); DataPtr += sizeof (DWORD); MYASSERT (DataSize == sizeof (VENDORINFO));
*VendorInfo = (PVENDORINFO) PoolMemDuplicateMemory (g_MigDllPool, DataPtr, sizeof (VENDORINFO)); DataPtr += sizeof (VENDORINFO); }
DEBUGMSG ((DBG_MIGDLLS, "QueryVersion is complete, rc=%u", rc)); }
__except(TRUE) { LOG ((LOG_ERROR, "An error occurred while unpacking params")); rc = ERROR_INVALID_PARAMETER; } } else { DEBUGMSG ((DBG_WARNING, "pRemoteQueryVersion: No OUT params received"));
//
// We should never return ERROR_SUCCESS if no buffer is received.
//
if (rc == ERROR_SUCCESS) { rc = ERROR_INVALID_PARAMETER; } } } __finally { FreeGrowBuffer (&GrowBuf); }
return rc; }
DWORD pRemoteInitialize9x( IN PCSTR WorkingDir, IN PCSTR SourceDirs, PVOID *Reserved, DWORD SizeOfReserved ) { DWORD rc = ERROR_SUCCESS; GROWBUFFER GrowBuf = GROWBUF_INIT; PCSTR p; PBYTE Data; DWORD ReturnSize;
pFreeGlobalIpcBuffer();
__try { //
// Send working dir and source dirs
//
MultiSzAppendA (&GrowBuf, WorkingDir);
for (p = SourceDirs ; *p ; p = GetEndOfStringA (p) + 1) { MultiSzAppendA (&GrowBuf, p); }
MultiSzAppendA (&GrowBuf, p); GrowBufAppendDword (&GrowBuf, SizeOfReserved);
if (SizeOfReserved) { Data = GrowBuffer (&GrowBuf, SizeOfReserved); CopyMemory (Data, *Reserved, SizeOfReserved); }
//
// Send command to migisol
//
if (!SendIpcCommand ( IPC_INITIALIZE, GrowBuf.Buf, GrowBuf.End )) {
LOG ((LOG_ERROR,"pRemoteInitialize9x failed to send command")); rc = GetLastError(); __leave; }
//
// Finish transaction. Caller will interpret return code.
//
rc = pFinishHandshake9x();
//
// The reserved parameter may come back
//
if (g_Data) { Data = g_Data; ReturnSize = *((PDWORD) Data); if (ReturnSize) { Data += sizeof (DWORD); CopyMemory (*Reserved, Data, ReturnSize); } else if (SizeOfReserved) { ZeroMemory (*Reserved, SizeOfReserved); } } } __finally { FreeGrowBuffer (&GrowBuf); }
return rc; }
VOID pGetParentWindowTitleAndId ( IN HWND ParentWnd, OUT PSTR TitleBuf, OUT PDWORD IdPtr ) { *IdPtr = 0;
if (ParentWnd) { GetWindowTextA (ParentWnd, TitleBuf, MAX_PATH); GetWindowThreadProcessId (ParentWnd, IdPtr); } else { TitleBuf[0] = 0; } }
DWORD pRemoteMigrateUser9x ( IN HWND ParentWnd, OPTIONAL IN PCSTR UnattendFile, IN PCSTR RootKey, IN PCSTR User OPTIONAL ) { DWORD rc = ERROR_SUCCESS; GROWBUFFER GrowBuf = GROWBUF_INIT; CHAR ParentWindowTitle[MAX_PATH]; DWORD ProcessId;
pGetParentWindowTitleAndId (ParentWnd, ParentWindowTitle, &ProcessId);
pFreeGlobalIpcBuffer();
__try { MultiSzAppendA (&GrowBuf, ParentWindowTitle); GrowBufAppendDword (&GrowBuf, ProcessId); MultiSzAppendA (&GrowBuf, UnattendFile); MultiSzAppendA (&GrowBuf, RootKey); MultiSzAppendA (&GrowBuf, (NULL == User ? S_EMPTY : User));
if (!SendIpcCommand ( IPC_MIGRATEUSER, GrowBuf.Buf, GrowBuf.End )) {
LOG ((LOG_ERROR, "pRemoteMigrateUser9x failed to send command")); rc = GetLastError(); __leave; }
//
// Complete the transaction. The caller will interpret the return
// value.
//
rc = pFinishHandshake9x();
//
// No data buffer is coming back at this time
//
}
__finally { FreeGrowBuffer (&GrowBuf); }
return rc; }
DWORD pRemoteMigrateSystem9x ( IN HWND ParentWnd, OPTIONAL IN PCSTR UnattendFile ) { DWORD rc = ERROR_SUCCESS; GROWBUFFER GrowBuf = GROWBUF_INIT; CHAR ParentWindowTitle[MAX_PATH]; DWORD ProcessId;
pGetParentWindowTitleAndId (ParentWnd, ParentWindowTitle, &ProcessId);
pFreeGlobalIpcBuffer();
__try { MultiSzAppendA (&GrowBuf, ParentWindowTitle); GrowBufAppendDword (&GrowBuf, ProcessId); MultiSzAppendA (&GrowBuf, UnattendFile);
if (!SendIpcCommand ( IPC_MIGRATESYSTEM, GrowBuf.Buf, GrowBuf.End )) {
LOG ((LOG_ERROR,"pRemoteMigrateSystem9x failed to send command")); rc = GetLastError(); __leave; }
//
// Finish transaction. Caller will interpret return value.
//
rc = pFinishHandshake9x();
//
// No data buffer is coming back at this time
//
}
__finally { FreeGrowBuffer (&GrowBuf); }
return rc; }
VOID pFreeGlobalIpcBuffer ( VOID ) { //
// Free old return param buffer
//
if (g_Data) { MemFree (g_hHeap, 0, g_Data); g_Data = NULL; }
g_DataSize = 0; }
DWORD pFinishHandshake9x( VOID ) { DWORD TechnicalLogId; DWORD GuiLogId; DWORD rc = ERROR_SUCCESS; DWORD DataSize = 0; PBYTE Data = NULL; BOOL b;
pFreeGlobalIpcBuffer();
do { b = GetIpcCommandResults ( IPC_GET_RESULTS_WIN9X, &Data, &DataSize, &rc, &TechnicalLogId, &GuiLogId );
if (g_AbortDllEvent) { if (WaitForSingleObject (g_AbortDllEvent, 0) == WAIT_OBJECT_0) { rc = ERROR_CANCELLED; break; } }
//
// Loop if no data received, but process is alive
//
if (!b) { if (!IsIpcProcessAlive()) { rc = ERROR_NOACCESS; break; }
if (*g_CancelFlagPtr) { rc = ERROR_CANCELLED; break; } }
} while (!b);
if (b) { //
// Save return param block and loop back for IPC_LOG or IPC_DONE
//
g_DataSize = DataSize; g_Data = Data;
//
// Recognize log messages
//
if (!CANCELLED()) { if (TechnicalLogId) {
//
// LOG message with three args: DllDesc, DllPath, User
//
LOG (( LOG_ERROR, (PCSTR) TechnicalLogId, g_DllPath, g_DllName, S_EMPTY, S_EMPTY )); } if (GuiLogId) { LOG (( LOG_ERROR, (PCSTR) GuiLogId, g_DllPath, g_DllName, S_EMPTY, S_EMPTY )); } } }
return rc; }
BOOL pIsCodePageArrayValid ( IN PDWORD CodePageArray ) { DWORD CodePage; UINT u;
if (!CodePageArray) { return TRUE; }
//
// Scan system's code pages
//
CodePage = GetACP();
__try { for (u = 0 ; CodePageArray[u] != -1 ; u++) { if (CodePage == CodePageArray[u]) { return TRUE; } } } __except (TRUE) { LOG ((LOG_ERROR, "Caugh an exception while validating array of code pages.")); }
return FALSE; }
LONG CallQueryVersion ( IN PCSTR WorkingDir, OUT PCSTR *ProductId, OUT PUINT DllVersion, OUT PCSTR *ExeNamesBuf, OUT PVENDORINFO *VendorInfo ) { PDWORD CodePageArray = NULL; LONG rc;
if (!g_UseMigIsol) { //
// Call the entry point directly
//
MYASSERT (TestQueryVersion);
*ProductId = NULL; *DllVersion = 1; *ExeNamesBuf = NULL; *VendorInfo = NULL;
SetCurrentDirectory (WorkingDir);
rc = TestQueryVersion ( ProductId, DllVersion, &CodePageArray, ExeNamesBuf, VendorInfo );
} else {
rc = pRemoteQueryVersion ( ProductId, DllVersion, &CodePageArray, ExeNamesBuf, WorkingDir, VendorInfo );
}
DEBUGMSG ((DBG_MIGDLLS, "VendorInfo pointer is 0x%X", *VendorInfo));
if (rc == ERROR_SUCCESS) { //
// Trim whitespace off of product ID
//
if (pValidateNonNullString (*ProductId)) { *ProductId = SkipSpace (*ProductId); if (pValidateBinary ((PBYTE) (*ProductId), SizeOfStringA (*ProductId))) { TruncateTrailingSpace ((PSTR) (*ProductId)); } }
//
// Validate inbound parameters
//
if (!pValidateNonNullString (*ProductId) || !pValidateIntArray (CodePageArray) || !pValidateMultiString (*ExeNamesBuf) || !pValidateBinary ((PBYTE) (*VendorInfo), sizeof (VENDORINFO)) ) { LOG ((LOG_ERROR, "One or more parameters from the DLL are invalid.")); return ERROR_NOT_INSTALLED; }
if (!pIsCodePageArrayValid (CodePageArray)) { return ERROR_NOT_INSTALLED; }
//
// Trim the product ID
//
if (ByteCountA (*ProductId) > MAX_PATH) { *CharCountToPointerA (*ProductId, MAX_PATH) = 0; }
//
// Make sure VENDORINFO is valid
//
if (!(*VendorInfo)) { LOG ((LOG_ERROR, "DLL %s did not provide a VENDORINFO struct", *ProductId)); return ERROR_NOT_INSTALLED; }
g_DllName = *ProductId; }
return rc; }
LONG CallInitialize9x ( IN PCSTR WorkingDir, IN PCSTR SourceDirList, IN OUT PVOID Reserved, IN DWORD ReservedSize ) { LONG rc; CHAR WorkingDirCopy[MAX_MBCHAR_PATH]; PSTR SourceDirListCopy = NULL; PCSTR p; PVOID CopyOfReserved;
if (!g_UseMigIsol) { //
// Call the entry point directly
//
MYASSERT (TestInitialize9x);
SetCurrentDirectory (WorkingDir);
//
// Make a copy of all the supplied params, so if the migration DLL changes
// them, the rest of the upgrade isn't changed.
//
StringCopyA (WorkingDirCopy, WorkingDir); p = SourceDirList; while (*p) { p = GetEndOfStringA (p) + 1; } p++;
SourceDirListCopy = AllocText (p - SourceDirList); MYASSERT (SourceDirListCopy); if (SourceDirListCopy) { CopyMemory (SourceDirListCopy, SourceDirList, p - SourceDirList); }
//
// Call the entry point
//
rc = TestInitialize9x ( WorkingDirCopy, SourceDirListCopy, Reserved );
FreeText (SourceDirListCopy);
} else {
//
// Call the entry point via migisol.exe. Make a copy of the
// reserved because currently reserved is only an IN (an
// undocumented feature actually).
//
CopyOfReserved = MemAlloc (g_hHeap, 0, ReservedSize); CopyMemory (CopyOfReserved, Reserved, ReservedSize);
rc = pRemoteInitialize9x ( WorkingDir, SourceDirList, &CopyOfReserved, ReservedSize );
//
// CopyOfReserved now has the return value. We don't
// use it currently.
//
MemFree (g_hHeap, 0, CopyOfReserved);
}
return rc; }
LONG CallMigrateUser9x ( IN HWND ParentWnd, IN PCSTR UserName, IN PCSTR UnattendTxt, IN OUT PVOID Reserved, IN DWORD ReservedSize ) { LONG rc; CHAR UserNameBuf[MAX_USER_NAME]; CHAR UnattendTxtCopy[MAX_USER_NAME]; PSTR UserNameCopy = NULL; HKEY UserHandle;
if (!g_UseMigIsol) { //
// Call the entry point directly
//
MYASSERT (TestMigrateUser9x);
//
// Prepare copies of params
//
if (UserName && *UserName) { UserNameCopy = UserNameBuf; StringCopyA (UserNameCopy, UserName); }
StringCopyA (UnattendTxtCopy, UnattendTxt);
MYASSERT(g_UserKey); if (!g_UserKey) { g_UserKey = S_EMPTY; }
UserHandle = OpenRegKeyStr (g_UserKey); if (!UserHandle) { DEBUGMSG ((DBG_WHOOPS, "Cannot open %s", g_UserKey)); return FALSE; }
//
// Call the migration DLL
//
rc = TestMigrateUser9x ( ParentWnd, UnattendTxtCopy, UserHandle, UserNameCopy, Reserved );
} else { //
// Call the entry point via migisol.exe
//
rc = pRemoteMigrateUser9x ( ParentWnd, UnattendTxt, g_UserKey, UserName ); }
return rc; }
LONG CallMigrateSystem9x ( IN HWND ParentWnd, IN PCSTR UnattendTxt, IN PVOID Reserved, IN DWORD ReservedSize ) { LONG rc; CHAR UnattendTxtCopy[MAX_MBCHAR_PATH];
if (!g_UseMigIsol) { //
// Call the entry point directly
//
MYASSERT (TestMigrateSystem9x);
StringCopyA (UnattendTxtCopy, UnattendTxt);
rc = TestMigrateSystem9x ( ParentWnd, UnattendTxtCopy, Reserved );
} else {
rc = pRemoteMigrateSystem9x ( ParentWnd, UnattendTxt );
}
g_DllName = NULL;
return rc; }
|