/**************************************************************************** Copyright (c) Microsoft Corporation 1998 All rights reserved ***************************************************************************/ #include "pch.h" #include "utils.h" #include "callback.h" #include "welcome.h" #include "compat.h" #include "serverdlg.h" #include "directory.h" #include "sif.h" #include "complete.h" #include "summary.h" #include "tasks.h" #include "setupdlg.h" #include "appldlg.h" #include "setup.h" #include "errorlog.h" // Must have this... extern "C" { #include #include // // SYSPREP globals // BOOL NoSidGen = FALSE; // always generate new SID BOOL PnP = FALSE; // always PNP the system BOOL FactoryPreinstall = FALSE; // NOT a Factory Pre-Install case BOOL bMiniSetup = TRUE; // Run Mini-Setup, not MSOOBE HINSTANCE ghInstance = NULL; // Global instance handle } DEFINE_MODULE("RIPREP"); // Globals HINSTANCE g_hinstance = NULL; WCHAR g_ServerName[ MAX_PATH ]; WCHAR g_MirrorDir[ MAX_PATH ]; WCHAR g_Language[ MAX_PATH ]; WCHAR g_ImageName[ MAX_PATH ]; WCHAR g_Architecture[ 16 ]; WCHAR g_Description[ REMOTE_INSTALL_MAX_DESCRIPTION_CHAR_COUNT ]; WCHAR g_HelpText[ REMOTE_INSTALL_MAX_HELPTEXT_CHAR_COUNT ]; WCHAR g_SystemRoot[ MAX_PATH ] = L"Mirror1\\userdata\\winnt"; WCHAR g_WinntDirectory[ MAX_PATH ]; WCHAR g_HalName[32]; WCHAR g_ProductId[4]; DWORD g_dwWinntDirLength; BOOLEAN g_fQuietFlag = FALSE; BOOLEAN g_fErrorOccurred = FALSE; BOOLEAN g_fRebootOnExit = FALSE; DWORD g_dwLogFileStartLow; DWORD g_dwLogFileStartHigh; PCRITICAL_SECTION g_pLogCritSect = NULL; HANDLE g_hLogFile = INVALID_HANDLE_VALUE; OSVERSIONINFO OsVersion; BOOLEAN g_CommandLineArgsValid = TRUE; BOOLEAN g_OEMDesktop = FALSE; // Constants #define NUMBER_OF_PAGES 15 #define SMALL_BUFFER_SIZE 256 #define OPTION_UNKNOWN 0 #define OPTION_DEBUG 1 #define OPTION_FUNC 2 #define OPTION_QUIET 3 #define OPTION_PNP 4 #define OPTION_OEMDESKTOP 5 // // Adds a page to the dialog. // void AddPage( LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, UINT idTitle, UINT idSubtitle ) { PROPSHEETPAGE psp; TCHAR szTitle[ SMALL_BUFFER_SIZE ]; TCHAR szSubTitle[ SMALL_BUFFER_SIZE ]; ZeroMemory( &psp, sizeof(psp) ); psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT | PSP_USETITLE; if ( id == IDD_WELCOME || id == IDD_COMPLETE ) { psp.dwFlags |= PSP_HIDEHEADER; } else { psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; if ( idTitle ) { DWORD dw; dw = LoadString( g_hinstance, idTitle, szTitle, ARRAYSIZE(szTitle) ); Assert( dw ); psp.pszHeaderTitle = szTitle; } else { psp.pszHeaderTitle = NULL; } if ( idSubtitle ) { DWORD dw; dw = LoadString( g_hinstance, idSubtitle , szSubTitle, ARRAYSIZE(szSubTitle) ); Assert( dw ); psp.pszHeaderSubTitle = szSubTitle; } else { psp.pszHeaderSubTitle = NULL; } } psp.pszTitle = MAKEINTRESOURCE( IDS_APPNAME ); psp.hInstance = ppsh->hInstance; psp.pszTemplate = MAKEINTRESOURCE(id); psp.pfnDlgProc = pfn; ppsh->phpage[ ppsh->nPages ] = CreatePropertySheetPage( &psp ); if ( ppsh->phpage[ ppsh->nPages ] ) ppsh->nPages++; } // // Creates the UI pages and kicks off the property sheet. // HRESULT WizardPages( ) { TraceFunc( "WizardPages( )\n" ); HRESULT hr; HPROPSHEETPAGE rPages[ NUMBER_OF_PAGES ]; PROPSHEETHEADER pshead; INT_PTR iResult; ZeroMemory( &pshead, sizeof(pshead) ); pshead.dwSize = sizeof(pshead); pshead.dwFlags = PSH_WIZARD97 | PSH_PROPTITLE | PSH_USEHICON | PSH_WATERMARK | PSH_HEADER; pshead.hInstance = g_hinstance; pshead.pszCaption = MAKEINTRESOURCE( IDS_APPNAME ); pshead.phpage = rPages; pshead.pszbmWatermark = MAKEINTRESOURCE( IDB_TITLEPAGE ); pshead.pszbmHeader = MAKEINTRESOURCE( IDB_HEADER ); AddPage( &pshead, IDD_WELCOME, WelcomeDlgProc, 0, 0 ); AddPage( &pshead, IDD_SERVER, ServerDlgProc, IDS_SERVER_TITLE, IDS_SERVER_SUBTITLE ); AddPage( &pshead, IDD_OSDIRECTORY, DirectoryDlgProc, IDS_DIRECTORY_TITLE, IDS_DIRECTORY_SUBTITLE ); AddPage( &pshead, IDD_DEFAULTSIF, SIFDlgProc, IDS_SIF_TITLE, IDS_SIF_SUBTITLE ); AddPage( &pshead, IDD_COMPAT, CompatibilityDlgProc, IDS_COMPAT_TITLE, IDS_COMPAT_SUBTITLE ); AddPage( &pshead, IDD_STOPSVCWRN, StopServiceWrnDlgProc, IDS_STOPSVC_TITLE, IDS_STOPSVC_SUBTITLE ); AddPage( &pshead, IDD_STOPSVC, DoStopServiceDlgProc, IDS_STOPSVC_TITLE, IDS_STOPSVC_SUBTITLE ); AddPage( &pshead, IDD_APPLICATIONS_RUNNING, ApplicationDlgProc, IDS_APPLICATION_TITLE, IDS_APPLICATION_SUBTITLE ); AddPage( &pshead, IDD_SUMMARY, SummaryDlgProc, IDS_FINISH_TITLE, IDS_FINISH_SUBTITLE ); AddPage( &pshead, IDD_COMPLETE, CompleteDlgProc, 0, 0 ); iResult = PropertySheet( &pshead ); switch(iResult) { case 0: hr = E_FAIL; break; default: hr = S_OK; break; } RETURN(hr); } // // IsWhiteSpace() // BOOL IsWhiteSpace( WCHAR ch ) { if ( ch <=32 ) return TRUE; return FALSE; } // // CheckWhichOption() DWORD CheckWhichOption( LPWSTR pszOption ) { WCHAR szOptions[ 32 ]; DWORD dw; #ifdef DEBUG if ( StrCmpNI( pszOption, L"debug", 5 ) == 0 ) return OPTION_DEBUG; if ( StrCmpNI( pszOption, L"func", 4 ) == 0 ) return OPTION_FUNC; #endif // Check for quiet flag dw = LoadString( g_hinstance, IDS_QUIET, szOptions, ARRAYSIZE( szOptions ) ); Assert( dw ); if ( StrCmpNI( pszOption, szOptions, wcslen(szOptions) ) == 0 ) return OPTION_QUIET; if ( StrCmpNI( pszOption, L"PNP", 3 ) == 0 ) return OPTION_PNP; // // By default, the Setup guys are going to remove all the desktop icons // during MiniSetup. We'd like to keep those around for riprep installs, // so by default, we're going to set some registry keys to keep the // user's desktop around. However, if the user gives us a -OEMDesktop flag, // then don't set these flags and allow the desktop to be cleaned up. // if( StrCmpNI( pszOption, L"OEMDesktop", 10 ) == 0 ) { return OPTION_OEMDESKTOP; } return OPTION_UNKNOWN; } // // ParseCommandLine() // void ParseCommandLine( LPWSTR lpCmdLine ) { WCHAR szPath[ MAX_PATH ]; LPWSTR psz = NULL; BOOL endOfCommandLine; // // Check to see if the command line has the servername on it. // g_ServerName[0] = L'\0'; if ( lpCmdLine[0] == L'\\' && lpCmdLine[1] == L'\\' ) { psz = StrChr( &lpCmdLine[2], L'\\' ); if ( psz && psz != &lpCmdLine[2] ) { ZeroMemory( g_ServerName, sizeof(g_ServerName) ); wcsncpy( g_ServerName, &lpCmdLine[2], (DWORD)(psz - &lpCmdLine[2]) ); } } // See if it is a quoted path as well if ( lpCmdLine[0] == L'\"' && lpCmdLine[1] == L'\\' && lpCmdLine[2] == L'\\' ) { psz = StrChr( &lpCmdLine[3], L'\\' ); if ( psz && psz != &lpCmdLine[3] ) { ZeroMemory( g_ServerName, sizeof(g_ServerName) ); wcsncpy( g_ServerName, &lpCmdLine[3], (DWORD)(psz - &lpCmdLine[3]) ); } } // See if there is a whitespace break psz = StrChr( lpCmdLine, L' ' ); if ( psz ) { // yes... search backwards from the whitespace for a slash. psz = StrRChr( lpCmdLine, psz, L'\\' ); } else { // no... search backwards from the end of the command line for a slash. psz = StrRChr( lpCmdLine, &lpCmdLine[ wcslen( lpCmdLine ) ], L'\\' ); } // Found the starting path, now try to set the current directory // to this. if ( psz ) { ZeroMemory( szPath, sizeof(szPath) ); wcsncpy( szPath, lpCmdLine, (DWORD)(psz - lpCmdLine) ); // If quoted, add a trailing quote to the path if ( lpCmdLine[0] == L'\"' ) { wcscat( szPath, L"\"" ); } DebugMsg( "Set CD to %s\n", szPath ); SetCurrentDirectory( szPath ); } // Parse for command line arguments if (!psz) { psz = lpCmdLine; } endOfCommandLine = FALSE; while (!endOfCommandLine && (*psz != L'\0')) { if ( *psz == '/' || *psz == '-' ) { LPWSTR pszStartOption = ++psz; while (*psz && !IsWhiteSpace( *psz ) ) psz++; if (*psz == L'\0') { endOfCommandLine = TRUE; } else { *psz = '\0'; // terminate } switch ( CheckWhichOption( pszStartOption ) ) { #ifdef DEBUG case OPTION_DEBUG: g_dwTraceFlags |= 0x80000000; // not defined, but not zero either break; case OPTION_FUNC: g_dwTraceFlags |= TF_FUNC; break; #endif case OPTION_QUIET: g_fQuietFlag = TRUE; break; case OPTION_PNP: PnP = !PnP; // toggle break; case OPTION_OEMDESKTOP: g_OEMDesktop = TRUE; // The user want to clean the desktop. break; case OPTION_UNKNOWN: MessageBoxFromMessage( NULL, MSG_USAGE, FALSE, MAKEINTRESOURCE(IDS_APPNAME), MB_OK ); g_CommandLineArgsValid = FALSE; } } psz++; } } // // GetWorkstationLanguage( ) // DWORD GetWorkstationLanguage( ) { TraceFunc( "GetWorkstationLanguage( )\n" ); DWORD dwErr = ERROR_SUCCESS; LANGID langID = GetSystemDefaultLangID( ); UINT uResult = GetLocaleInfo( langID, LOCALE_SENGLANGUAGE, g_Language, ARRAYSIZE(g_Language) ); if ( uResult == 0 ) { DWORD dw; dwErr = GetLastError( ); dw = LoadString( g_hinstance, IDS_DEFAULT_LANGUAGE, g_Language, ARRAYSIZE(g_Language)); Assert( dw ); } RETURN(dwErr); } BOOLEAN GetInstalledProductType( PDWORD Type, PDWORD Mask ); // // GetProductSKUNumber // DWORD GetProductSKUNumber( VOID ) /*++ Routine Description: Determine SKU number of installation, which should match the producttype value in txtsetup.sif Arguments: none. Return value: product sku number. if it fails, we set the return value to 0, which is the sku code for professional. --*/ { TraceFunc( "GetProductSKUNumber( )\n" ); DWORD ProductType, ProductSuiteMask; if (!GetInstalledProductType( &ProductType, &ProductSuiteMask )) { return 0; } if (ProductType == VER_NT_SERVER) { if (ProductSuiteMask & VER_SUITE_DATACENTER) { return 3; } if (ProductSuiteMask & VER_SUITE_ENTERPRISE) { return 2; } return 1; } if (ProductSuiteMask & VER_SUITE_PERSONAL) { return 4; } return 0; } // // GetHalName( ) // DWORD GetHalName( VOID ) /*++ Routine Description: Determine the actual name of the HAL running on the system. The actual name of the hal is stored in the originalfilename in the version resource. Arguments: none. Return value: Win32 error code indicating outcome. --*/ { TraceFunc( "GetHalName( )\n" ); DWORD dwErr = ERROR_GEN_FAILURE; WCHAR HalPath[MAX_PATH]; DWORD VersionHandle; DWORD FileVersionInfoSize; PVOID VersionInfo = NULL; DWORD *Language,LanguageSize; WCHAR OriginalFileNameString[64]; PWSTR ActualHalName; // // the hal is in system32 directory, build a path to it. // if (!GetSystemDirectory(HalPath,ARRAYSIZE(HalPath))) { dwErr = GetLastError(); goto exit; } wcscat(HalPath, L"\\hal.dll" ); // // you must call GetFileVersionInfoSize,GetFileVersionInfo before // you can call VerQueryValue() // FileVersionInfoSize = GetFileVersionInfoSize(HalPath, &VersionHandle); if (FileVersionInfoSize == 0) { goto exit; } VersionInfo = LocalAlloc( LPTR, FileVersionInfoSize ); if (VersionInfo == NULL) { goto exit; } if (!GetFileVersionInfo( HalPath, 0, //ignored FileVersionInfoSize, VersionInfo)) { goto exit; } // // ok, get the language of the file so we can look in the correct // StringFileInfo section for the file name // if (!VerQueryValue( VersionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&Language, (PUINT)&LanguageSize)) { goto exit; } wsprintf( OriginalFileNameString, L"\\StringFileInfo\\%04x%04x\\OriginalFilename", LOWORD(*Language), HIWORD(*Language)); // // now retreive the actual OriginalFilename. // if (!VerQueryValue( VersionInfo, OriginalFileNameString, (LPVOID*)&ActualHalName, (PUINT)&LanguageSize)) { goto exit; } // // store this off in a global so we can use it later on // wcscpy(g_HalName ,ActualHalName); dwErr = ERROR_SUCCESS; exit: if (VersionInfo) { LocalFree( VersionInfo ); } RETURN(dwErr); } // // VerifyWorkstation( ) // BOOL VerifyWorkstation( ) { TraceFunc( "VerifyWorkstation( )\n" ); HKEY hkey; LONG lResult; WCHAR szProductType[50] = { 0 }; DWORD dwType; DWORD dwSize = ARRAYSIZE(szProductType); BOOL fReturn = TRUE; // assume that we are not on NTServer. // Query the registry for the product type. lResult = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hkey); Assert( lResult == ERROR_SUCCESS ); if ( lResult != ERROR_SUCCESS ) goto Error; lResult = RegQueryValueEx ( hkey, L"ProductType", NULL, &dwType, (LPBYTE) szProductType, &dwSize); Assert( lResult == ERROR_SUCCESS ); RegCloseKey (hkey); if (lResult != ERROR_SUCCESS) goto Error; if ( StrCmpI( szProductType, L"ServerNT" ) == 0 ) { fReturn = FALSE; // NT Server } if ( StrCmpI( szProductType, L"LanmanNT" ) == 0 ) { fReturn = FALSE; // NT Server } Error: RETURN(fReturn); } // // CheckUserPermissions( ) // BOOL CheckUserPermissions( ) { TraceFunc( "CheckUserPermissions( )\n" ); if( !pSetupIsUserAdmin() || !pSetupDoesUserHavePrivilege(SE_SHUTDOWN_NAME) || !pSetupDoesUserHavePrivilege(SE_BACKUP_NAME) || !pSetupDoesUserHavePrivilege(SE_RESTORE_NAME) || !pSetupDoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) { RETURN(FALSE); } RETURN(TRUE); } // // GetProcessorType( ) // DWORD GetProcessorType( ) { TraceFunc( "GetProcessorType( )\n" ); DWORD dwErr = ERROR_INVALID_PARAMETER; SYSTEM_INFO si; GetSystemInfo( &si ); switch (si.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_ALPHA: wcscpy( g_Architecture, L"Alpha" ); break; case PROCESSOR_ARCHITECTURE_INTEL: dwErr = ERROR_SUCCESS; wcscpy( g_Architecture, L"i386" ); break; case PROCESSOR_ARCHITECTURE_IA64: //dwErr = ERROR_SUCCESS; wcscpy( g_Architecture, L"ia64" ); break; case PROCESSOR_ARCHITECTURE_UNKNOWN: default: break; } RETURN(dwErr); } // // WinMain() // int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TraceFunc( "WinMain( ... )\n" ); HANDLE hMutex; HRESULT hr = E_FAIL; IMIRROR_CALLBACK Callbacks; HWND hwndTasks = NULL; LPWSTR pszCommandLine = GetCommandLine( ); BOOL fDC = FALSE; g_hinstance = hInstance; ghInstance = hInstance; INITIALIZE_TRACE_MEMORY_PROCESS; pSetupInitializeUtils(); // allow only one instance running at a time hMutex = CreateMutex( NULL, TRUE, L"RIPREP.Mutext"); if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBoxFromStrings( NULL, IDS_ALREADY_RUNNING_TITLE, IDS_ALREADY_RUNNING_MESSAGE, MB_OK | MB_ICONSTOP ); goto Cleanup; } // parse command line arguments ParseCommandLine( pszCommandLine ); if (!g_CommandLineArgsValid) { goto Cleanup; } // // Gather os version info. // OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&OsVersion); // determine the language of the workstation GetWorkstationLanguage( ); if (ERROR_SUCCESS != GetHalName()) { MessageBoxFromStrings( NULL, IDS_INVALID_ARCHITECTURE_TITLE, IDS_INVALID_ARCHITECTURE_TEXT, MB_OK ); goto Cleanup; } wsprintf( g_ProductId, L"%d", GetProductSKUNumber() ); ProcessCompatibilityData(); // determine the processor type if ( GetProcessorType( ) != ERROR_SUCCESS ) { MessageBoxFromStrings( NULL, IDS_INVALID_ARCHITECTURE_TITLE, IDS_INVALID_ARCHITECTURE_TEXT, MB_OK ); goto Cleanup; } if ( !CheckUserPermissions( ) ) { MessageBoxFromStrings( NULL, IDS_MUST_BE_ADMINISTRATOR_TITLE, IDS_MUST_BE_ADMINISTRATOR_TEXT, MB_OK ); goto Cleanup; } #if 0 // // No longer limited to only workstation - adamba 4/6/00 // if ( !VerifyWorkstation( ) ) { MessageBoxFromStrings( NULL, IDS_MUST_BE_WORKSTATION_TITLE, IDS_MUST_BE_WORKSTATION_TEXT, MB_OK ); goto Cleanup; } #endif // get the name of the "Winnt" directory GetEnvironmentVariable( L"windir", g_WinntDirectory, ARRAYSIZE(g_WinntDirectory)); g_dwWinntDirLength = wcslen( g_WinntDirectory ); // setup IMIRROR.DLL callbacks Callbacks.Context = 0; Callbacks.ErrorFn = &ConvTestErrorFn; Callbacks.GetSetupFn = &ConvTestGetSetupFn; Callbacks.NowDoingFn = &ConvTestNowDoingFn; Callbacks.FileCreateFn = &ConvTestFileCreateFn; Callbacks.RegSaveErrorFn = NULL; Callbacks.ReinitFn = &ConvTestReinitFn; Callbacks.GetMirrorDirFn = &ConvTestGetMirrorDirFn; Callbacks.SetSystemDirFn = &ConvTestSetSystemFn; Callbacks.AddToDoFn = &ConvAddToDoItemFn; Callbacks.RemoveToDoFn = &ConvRemoveToDoItemFn; Callbacks.RebootFn = &ConvRebootFn; IMirrorInitCallback(&Callbacks); // show property pages hr = WizardPages( ); if ( hr != S_OK ) goto Cleanup; // complete tasks... ignore the return code, not important BeginProcess( hwndTasks ); // Display any errors recorded in the log, unless we are supposed // to reboot now. if ( g_fErrorOccurred && !g_fRebootOnExit ) { HINSTANCE hRichedDLL; // Make sure the RichEdit control has been initialized. // Simply LoadLibbing it does this for us. hRichedDLL = LoadLibrary( L"RICHED32.DLL" ); if ( hRichedDLL != NULL ) { DialogBox( g_hinstance, MAKEINTRESOURCE( IDD_VIEWERRORS ), g_hMainWindow, ErrorsDlgProc ); FreeLibrary (hRichedDLL); } } Cleanup: if (g_hCompatibilityInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile( g_hCompatibilityInf ); } CleanupCompatibilityData(); if ( hMutex ) CloseHandle( hMutex ); pSetupUninitializeUtils(); UNINITIALIZE_TRACE_MEMORY; if ( g_fRebootOnExit ) { (VOID)DoShutdown(TRUE); // TRUE tells it to restart } RETURN(hr); }