/*++ Copyright (c) 1996 Microsoft Corporation Module Name: dllentry.c Abstract: Code that implements the external DLL routines that interface with WINNT32. Author: Jim Schmidt (jimschm) 01-Oct-1996 Revision History: marcw 23-Sep-1998 Added Winnt32VirusScannerCheck jimschm 30-Dec-1997 Moved initializion to init.lib jimschm 21-Nov-1997 Updated for NEC98, cleaned up and commented code --*/ #include "pch.h" extern BOOL g_Terminated; BOOL WINAPI DllMain ( IN HINSTANCE hInstance, IN DWORD dwReason, IN LPVOID lpReserved ) /*++ Routine Description: DllMain cannot be counted on for anything. Do not put any code here!! Arguments: hInstance - Specifies the instance handle of the DLL (and not the parent EXE or DLL) dwReason - Specifies DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH. We specifically disable DLL_THREAD_ATTACH and DLL_THREAD_DETACH. lpReserved - Unused. Return Value: DLL_PROCESS_ATTACH: TRUE if initialization completed successfully, or FALSE if an error occurred. The DLL remains loaded only if TRUE is returned. DLL_PROCESS_DETACH: Always TRUE. other: unexpected, but always returns TRUE. --*/ { if (dwReason == DLL_PROCESS_ATTACH) { g_hInst = hInstance; } return TRUE; } DWORD CALLBACK Winnt32PluginInit ( IN PWINNT32_PLUGIN_INIT_INFORMATION_BLOCK Info ) /*++ Routine Description: Winnt32PluginInit is called when WINNT32 first loads w95upg.dll, before any wizard pages are displayed. The structure supplies pointers to WINNT32's variables that will be filled with valid values as WINNT32 runs. Control is passed to the code in init9x.lib. Arguments: Info - Specifies the WINNT32 variables the upgrade module needs access to. Note that this is actually a PWINNT32_WIN9XUPG_INIT_INFORMATION_BLOCK (which itself holds the normal initialization block..) Return Value: A Win32 status code indicating outcome. --*/ { LONG Result = ERROR_SUCCESS; PWINNT32_WIN9XUPG_INIT_INFORMATION_BLOCK win9xInfo = (PWINNT32_WIN9XUPG_INIT_INFORMATION_BLOCK) Info; __try { // // Get dll path information from the Info block. We need to set this first because // some initialization routines depend on it being set correctly. Because we may have // been loaded using dll replacement, we can't assume that the rest of our files are // in the same directory as us.. Winnt32 provides us with the correct information in // the UpgradeSourcePath variable of the win9xInfo. // MYASSERT (win9xInfo->UpgradeSourcePath && *win9xInfo->UpgradeSourcePath); StringCopy (g_UpgradeSources, win9xInfo->UpgradeSourcePath); // // Initialize DLL globals // if (!FirstInitRoutine (g_hInst)) { Result = ERROR_DLL_INIT_FAILED; __leave; } // // Initialize all libraries // if (!InitLibs (g_hInst, DLL_PROCESS_ATTACH, NULL)) { Result = ERROR_DLL_INIT_FAILED; __leave; } // // Final initialization // if (!FinalInitRoutine ()) { Result = ERROR_DLL_INIT_FAILED; __leave; } Result = Winnt32Init (win9xInfo); } __finally { if (Result != ERROR_SUCCESS && Result != ERROR_REQUEST_ABORTED) { Winnt32Cleanup(); } } return Result; } #define S_VSCANDBINF TEXT("vscandb.inf") BOOL CALLBACK Winnt32VirusScannerCheck ( VOID ) { HANDLE snapShot; PROCESSENTRY32 process; HANDLE processHandle; WIN32_FIND_DATA findData; FILE_HELPER_PARAMS fileParams; HANDLE findHandle; PTSTR infFile; PTSTR p; UINT i; UINT size; g_BadVirusScannerFound = FALSE; infFile = JoinPaths (g_UpgradeSources, S_VSCANDBINF); // // Initialize migdb from vscandb.inf. // if (!InitMigDbEx (infFile)) { DEBUGMSG ((DBG_ERROR, "Could not initialize migdb with virus scanner information. infFile: %s", infFile)); FreePathString (infFile); return TRUE; } FreePathString (infFile); // // Take snapshot of the system (will contain a list of all // the 32 bit processes running) // snapShot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); if (snapShot != INVALID_HANDLE_VALUE) { // // Enumerate all the processes and check the executables they ran from against the vscandb. // process.dwSize = sizeof (PROCESSENTRY32); if (Process32First (snapShot, &process)) { do { // // We need to fill in the file helper params structure and pass it to migdb to test against // known bad virus scanners. // ZeroMemory (&fileParams, sizeof(FILE_HELPER_PARAMS)); fileParams.FullFileSpec = process.szExeFile; p = _tcsrchr (process.szExeFile, TEXT('\\')); if (p) { *p = 0; StringCopy (fileParams.DirSpec, process.szExeFile); *p = TEXT('\\'); } fileParams.Extension = GetFileExtensionFromPath (process.szExeFile); findHandle = FindFirstFile (process.szExeFile, &findData); if (findHandle != INVALID_HANDLE_VALUE) { fileParams.FindData = &findData; FindClose (findHandle); } fileParams.VirtualFile = FALSE; // // Now that we have filled in the necessary information, test the file against // our database of bad virus scanners. If the process *is* a bad virus scanner, // then the necessary globals will have been filled in by the migdb action // associated with these types of incompatibilities. // MigDbTestFile (&fileParams); } while (Process32Next (snapShot, &process)); } ELSE_DEBUGMSG ((DBG_WARNING, "No processes to enumerate found on the system. No virus scanner checking done.")); // // Now, terminate any files that were added to the badvirusscanner growlist. // size = GrowListGetSize (&g_BadVirusScannerGrowList); if (!g_BadVirusScannerFound && size && Process32First (snapShot, &process)) { do { for (i = 0; i < size; i++) { p = (PTSTR) GrowListGetString (&g_BadVirusScannerGrowList, i); if (StringIMatch (p, process.szExeFile)) { processHandle = OpenProcess (PROCESS_TERMINATE, FALSE, process.th32ProcessID); if (processHandle == INVALID_HANDLE_VALUE || !TerminateProcess (processHandle, 0)) { g_BadVirusScannerFound = TRUE; DEBUGMSG ((DBG_ERROR, "Unable to kill process %s.", process.szExeFile)); } } } } while (Process32Next (snapShot, &process)); } CloseHandle (snapShot); } ELSE_DEBUGMSG ((DBG_WARNING, "Could not enumerate processes on the system. No Virus scanner checking done.")); FreeGrowList (&g_BadVirusScannerGrowList); CleanupMigDb (); if (g_BadVirusScannerFound) { DEBUGMSG ((DBG_WARNING, "Virus scanner found. Setup will not continue until the user deletes this process.")); return FALSE; } return TRUE; } PTSTR CALLBACK Winnt32GetOptionalDirectories ( VOID ) { if (!CANCELLED()) { return GetNeededLangDirs (); } else { return NULL; } } DWORD CALLBACK Winnt32PluginGetPages ( OUT UINT *FirstCountPtr, OUT PROPSHEETPAGE **FirstArray, OUT UINT *SecondCountPtr, OUT PROPSHEETPAGE **SecondArray, OUT UINT *ThirdCountPtr, OUT PROPSHEETPAGE **ThirdArray ) /*++ Routine Description: Winnt32PluginGetPages is called right after Winnt32PluginInit. We return three arrays of wizard pages, and WINNT32 inserts them into its master wizard page array. Because no wizard pages have been displayed, the user has not yet chosen the upgrade or fresh install option. Therefore, all our wizard pages get called in all cases, so we must remember NOT to do any processong in fresh install. Arguments: FirstCountPtr - Receives the number of pages in FirstArray and can be zero. FirstArray - Receives a pointer to an array of FirstCountPtr property sheet page structs. SecondCountPtr - Receives the number of pages in SecondArray and can be zero. SecondArray - Receives a pointer to an array of SecondCountPtr property sheet page structs. ThirdCountPtr - Receives the number of pages in ThirdArray and can be zero. ThirdArray - Receives a pointer to an array of ThirdCountPtr property sheet page structs. See WINNT32 for more information on where these wizard pages are inserted into the master wizard page list. Return Value: A Win32 status code indicating outcome. --*/ { return UI_GetWizardPages (FirstCountPtr, FirstArray, SecondCountPtr, SecondArray, ThirdCountPtr, ThirdArray); } DWORD CALLBACK Winnt32WriteParams ( IN PCTSTR WinntSifFile ) /*++ Routine Description: Winnt32WriteParams is called just before WINNT32 begins to modify the boot sector and copy files. Our job here is to take the specified WINNT.SIF file, read it in, merge in our changes, and write it back out. The actual work is done in the init9x.lib code. Arguments: WinntSifFile - Specifies path to WINNT.SIF. By this time, the WINNT.SIF file has some values already set. Return Value: A Win32 status code indicating outcome. --*/ { if (UPGRADE()) { return Winnt32WriteParamsWorker (WinntSifFile); } return ERROR_SUCCESS; } VOID CALLBACK Winnt32Cleanup ( VOID ) /*++ Routine Description: If the user cancels Setup, Winnt32Cleanup is called while WINNT32 is displaying the wizard page "Setup is undoing changes it made to your computer." We must stop all processing and clean up. If WINNT32 completes all of its work, Winnt32Cleanup is called as the process exists. We get called even on fresh install, so we must verify we are upgrading. Arguments: none Return Value: none --*/ { if (g_Terminated) { return; } if (UPGRADE()) { Winnt32CleanupWorker(); } // // Call the cleanup routine that requires library APIs // FirstCleanupRoutine(); // // Clean up all libraries // TerminateLibs (g_hInst, DLL_PROCESS_DETACH, NULL); // // Do any remaining clean up // FinalCleanupRoutine(); } BOOL CALLBACK Winnt32SetAutoBoot ( IN INT DriveLetter ) /*++ Routine Description: Winnt32SetAutoBoot is called by WINNT32 on both upgrade and fresh install to modify the boot partition of a NEC PC-9800 Partition Control Table. Control is passed to the init9x.lib code. Arguments: DriveLetter - Specifies the boot drive letter Return Value: TRUE if the partition control table was updated, or FALSE if it wasn't, or an error occurred. --*/ { return Winnt32SetAutoBootWorker (DriveLetter); } BOOL CALLBACK Win9xGetIncompDrvs ( OUT PSTR** IncompatibleDrivers ) { HARDWARE_ENUM e; GROWBUFFER listDevicePnpids; GROWBUFFER listUnsupDrv = GROWBUF_INIT; PCTSTR multisz; if (!IncompatibleDrivers) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } *IncompatibleDrivers = NULL; MYASSERT (g_SourceDirectoriesFromWinnt32 && g_SourceDirectoryCountFromWinnt32); if (!(g_SourceDirectoriesFromWinnt32 && g_SourceDirectoryCountFromWinnt32)) { DEBUGMSG (( DBG_ERROR, "Win9xAnyNetDevicePresent: upgrade module was not initialized" )); return TRUE; } if (!CreateNtHardwareList ( g_SourceDirectoriesFromWinnt32, *g_SourceDirectoryCountFromWinnt32, NULL, REGULAR_OUTPUT )) { DEBUGMSG (( DBG_ERROR, "Win9xupgGetIncompatibleDrivers: CreateNtHardwareList failed!" )); return FALSE; } // // ISSUE - is this enumerating unsupported drivers as well? // if (EnumFirstHardware (&e, ENUM_INCOMPATIBLE_DEVICES, 0)) { do { if (!(e.HardwareID && *e.HardwareID) && !(e.CompatibleIDs && *e.CompatibleIDs)) { continue; } LOG (( LOG_INFORMATION, "Win9xupgGetIncompatibleDrivers: Found Incompatible Device:\r\n" "Name: %s\r\nMfg: %s\r\nHardwareID: %s\r\nCompatibleIDs: %s\r\nHWRevision: %s", e.DeviceDesc, e.Mfg, e.HardwareID, e.CompatibleIDs, e.HWRevision )); ZeroMemory (&listDevicePnpids, sizeof (listDevicePnpids)); if (e.HardwareID && *e.HardwareID) { AddPnpIdsToGrowBuf (&listDevicePnpids, e.HardwareID); } if (e.CompatibleIDs && *e.CompatibleIDs) { AddPnpIdsToGrowBuf (&listDevicePnpids, e.CompatibleIDs); } GrowBufAppendDword (&listUnsupDrv, (DWORD)listDevicePnpids.Buf); } while (EnumNextHardware (&e)); } // // terminate the list with a NULL // GrowBufAppendDword (&listUnsupDrv, (DWORD)NULL); if (listUnsupDrv.Buf) { *IncompatibleDrivers = (PSTR*)listUnsupDrv.Buf; } return TRUE; } VOID CALLBACK Win9xReleaseIncompDrvs ( IN PSTR* IncompatibleDrivers ) { GROWBUFFER listDevicePnpids = GROWBUF_INIT; GROWBUFFER listUnsupDrv = GROWBUF_INIT; if (IncompatibleDrivers) { listUnsupDrv.Buf = (PBYTE)IncompatibleDrivers; while (*IncompatibleDrivers) { listDevicePnpids.Buf = (PBYTE)(*IncompatibleDrivers); FreeGrowBuffer (&listDevicePnpids); IncompatibleDrivers++; } FreeGrowBuffer (&listUnsupDrv); } } BOOL CALLBACK Win9xAnyNetDevicePresent ( VOID ) { HARDWARE_ENUM e; #if 0 MYASSERT (g_SourceDirectoriesFromWinnt32 && g_SourceDirectoryCountFromWinnt32); if (!(g_SourceDirectoriesFromWinnt32 && g_SourceDirectoryCountFromWinnt32)) { DEBUGMSG (( DBG_ERROR, "Win9xAnyNetDevicePresent: upgrade module was not initialized" )); return TRUE; } if (!CreateNtHardwareList ( g_SourceDirectoriesFromWinnt32, *g_SourceDirectoryCountFromWinnt32, NULL, REGULAR_OUTPUT )) { DEBUGMSG (( DBG_ERROR, "Win9xAnyNetDevicePresent: failed to create the NT hardware list" )); // // assume there is one // return TRUE; } #endif if (EnumFirstHardware (&e, ENUM_ALL_DEVICES, ENUM_DONT_REQUIRE_HARDWAREID)) { do { // // Enumerate all PNP devices of class Net // if (e.Class) { if (StringIMatch (e.Class, TEXT("net")) || StringIMatch (e.Class, TEXT("modem")) ) { AbortHardwareEnum (&e); return TRUE; } } } while (EnumNextHardware (&e)); } return FALSE; }