/************************************************************************** * * OEMRESET * * Microsoft Confidential * Copyright (c) Microsoft Corporation 1999 * All rights reserved * * Main entry point * * Command line: /A /Auto: Enduser reboot * /S : Enduser power-down * /R : Audit reboot * /P : Audit power-down * /H : Hide dialog * /L : OEM logging enabled (c:\reset.txt) * * Revision History: * 7/00 - Brian Ku (briank) Port from Millennium to Whistler. * 5/01 - Adrian Cosma (acosma) Remove dead code and integrate more with sysprep.c. * * *************************************************************************/ #include #include #pragma warning( disable:4001 ) /* Disable new type remark warning */ #pragma warning( disable:4100 ) /* Disable unreferenced formal param */ #include #include #include #include #include "sysprep.h" #include "msg.h" #include "resource.h" // Action flags // extern BOOL NoSidGen; extern BOOL SetupClPresent; extern BOOL bMiniSetup; extern BOOL PnP; extern BOOL Reboot; extern BOOL NoReboot; extern BOOL ForceShutdown; extern BOOL bActivated; extern BOOL Reseal; extern BOOL Factory; extern BOOL Audit; extern BOOL QuietMode; extern TCHAR g_szLogFile[]; extern BOOL IsProfessionalSKU(); extern BOOL FProcessSwitches(); extern int MessageBoxFromMessage( IN DWORD MessageId, IN DWORD CaptionStringId, IN UINT Style, ... ); //*************************************************************************** // // Definitions // //*************************************************************************** // Audit modes // #define MODE_NO_AUDIT 0 #define MODE_RESTORE_AUDIT 2 #define MODE_SIMULATE_ENDUSER 3 // User defined messages // #define WM_PROGRESS (WM_USER + 0x0001) #define WM_FINISHED (WM_USER + 0x0002) // Flags used for command line parsing // #define OEMRESET_AUTO 0x0001 // Auto /A or /AUTO #define OEMRESET_SHUTDOWN 0x0002 // Shutdown /S #define OEMRESET_AUDIT 0x0004 // Audit reboot /R #define OEMRESET_AUDITPD 0x0008 // Audit power-down, when booted back up, you will still be in audit mode #define OEMRESET_HIDE 0x0010 // Hide dialog /H #define OEMRESET_LOG 0x0020 // Log enabled /L #define OEMRESET_OEMRUN 0x0040 // Launch oemrun items // Configuration files/directories // #define DIR_BOOT _T("BootDir") #define FILE_RESET_LOG _T("RESETLOG.TXT") #define FILE_AFX_TXT _T("\\OPTIONS\\AFC.TXT") // Other constants // #define REBOOT_SECONDS 30 // Global Variables // HWND ghwndOemResetDlg = 0; // HWND for OemReset Dialog HINSTANCE ghinstEXE = 0; DWORD gdwCmdlineFlags = 0; // Switches used BOOL gbHide = FALSE; // Hide all dialogs BOOL gbLog = FALSE; // Enable logging HFILE ghf = 0; // Log file handle HANDLE ghMonitorThread = 0; DWORD gdwThreadID = 0; UINT_PTR gTimerID = 1; // Wait timer id UINT gdwMillSec = 120 * 1000; // Wait millsec HWND ghwndProgressCtl; // Wait progress controls /* Local Prototypes */ static HWND CreateOemResetDlg(HINSTANCE hInstance); static void FlushAndDisableRegistry(); static BOOL FShutdown(); static BOOL ParseCmdLineSwitches(LPTSTR); static TCHAR* ParseRegistrySwitches(); static void StartMonitorKeyValue(); static void HandleCommandSwitches(); static BOOL VerifySids(); /* Dialog functions */ INT_PTR CALLBACK RemindeOEMDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); void uiDialogTopRight(HWND hwndDlg); ////////////////////////////////////////////////////////////////////////////// // Create the OEMRESET Dialog modeless so we can hide it if necessary // HWND CreateOemResetDlg(HINSTANCE hInstance) { return CreateDialog(hInstance, MAKEINTRESOURCE(IDD_OEMREMINDER), NULL, RemindeOEMDlgProc); } ////////////////////////////////////////////////////////////////////////////// // Find the boot drive in the registry // void GetBootDrive(TCHAR szBootDrive[]) { HKEY hKey = 0; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_CURRENTVERSION_SETUP, &hKey) == ERROR_SUCCESS) { DWORD dwSize = MAX_PATH; RegQueryValueEx(hKey, DIR_BOOT, 0L, NULL, (LPBYTE)szBootDrive, &dwSize); RegCloseKey(hKey); } } ////////////////////////////////////////////////////////////////////////////// // Sets the flag determined by whether the dialog checkbox is checked or not // void SetFlag(HWND hDlg, WPARAM ctlId, BOOL* pfFlag) { if (pfFlag) { if (IsDlgButtonChecked(hDlg, (INT)ctlId)) *pfFlag = TRUE; else *pfFlag = FALSE; } } ////////////////////////////////////////////////////////////////////////////// // Sets the flag determined by whether the dialog checkbox is checked or not // void SetCheck(HWND hDlg, WPARAM ctlId, BOOL fFlag) { if (fFlag) CheckDlgButton(hDlg, (INT)ctlId, BST_CHECKED); else CheckDlgButton(hDlg, (INT)ctlId, BST_UNCHECKED); } extern StartWaitThread(); ////////////////////////////////////////////////////////////////////////////// // Put up UI telling the OEM that they still have to execute this. // INT_PTR CALLBACK RemindeOEMDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: // Quiet is always FALSE when the UI is up. // QuietMode = FALSE; // IA64 always use mini-setup // if (IsIA64()) { SetCheck(hwnd, IDC_MINISETUP, bMiniSetup = TRUE); EnableWindow(GetDlgItem(hwnd, IDC_MINISETUP), FALSE); } else { // Set check depending on flag // SetCheck(hwnd, IDC_MINISETUP, bMiniSetup); // Only Professional SKU can use both oobe or mini-setup otherwise // disable the checkbox // if (!IsProfessionalSKU()) EnableWindow(GetDlgItem(hwnd, IDC_MINISETUP), FALSE); } // Disable the pnp checkbox if mini-setup is not checked. // if ( !bMiniSetup ) EnableWindow(GetDlgItem(hwnd, IDC_PNP), FALSE); else SetCheck(hwnd, IDC_PNP, PnP); SetCheck(hwnd, IDC_NOSIDGEN, NoSidGen); SetCheck(hwnd, IDC_ACTIVATED, bActivated); // If setupcl.exe is not present and they specified nosidgen // then we need to disable the checkbox // if ( !SetupClPresent && NoSidGen ) EnableWindow(GetDlgItem(hwnd, IDC_NOSIDGEN), FALSE); // Disable Audit button if we are not in factory mode and change the caption. // if ( !RegCheck(HKLM, REGSTR_PATH_SYSTEM_SETUP, REGSTR_VALUE_AUDIT) ) { EnableWindow(GetDlgItem(hwnd, IDAUDIT), FALSE); } // Init the combo box. // { HWND hCombo = NULL; if (hCombo = GetDlgItem(hwnd, IDC_SHUTDOWN)) { TCHAR szComboString[MAX_PATH] = _T(""); LRESULT ret = 0; if ( LoadString(ghinstEXE, IDS_SHUTDOWN, szComboString, sizeof(szComboString)/sizeof(szComboString[0])) && ((ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szComboString)) != CB_ERR) ) { SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) NULL); } if ( LoadString(ghinstEXE, IDS_REBOOT, szComboString, sizeof(szComboString)/sizeof(szComboString[0])) && ((ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szComboString)) != CB_ERR) ) { SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) &Reboot); } if ( LoadString(ghinstEXE, IDS_QUIT, szComboString, sizeof(szComboString)/sizeof(szComboString[0])) && ((ret = SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szComboString)) != CB_ERR) ) { SendMessage(hCombo, CB_SETITEMDATA, ret, (LPARAM) &NoReboot); } if (NoReboot) SendMessage(hCombo, CB_SETCURSEL, (WPARAM) 2, 0); else if (Reboot) SendMessage(hCombo, CB_SETCURSEL, (WPARAM) 1, 0); else SendMessage(hCombo, CB_SETCURSEL, (WPARAM) 0, 0); } } uiDialogTopRight(hwnd); LockApplication(FALSE); break; case WM_CLOSE: LockApplication(FALSE); break; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDCANCEL: PostQuitMessage(0); break; // Action buttons // case IDOK: // Reseal // Check whether SIDS have been regenerated and try to help the user // make a smart decision about doing it again. if ( !VerifySids() ) { SetFocus(GetDlgItem(hwnd, IDC_NOSIDGEN)); return FALSE; } if ( !LockApplication(TRUE) ) { MessageBoxFromMessage( MSG_ALREADY_RUNNING, IDS_APPTITLE, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; } Reseal = TRUE; // Reseal the machine // FProcessSwitches(); LockApplication(FALSE); break; case IDAUDIT: { // Prepare for pseudo factory but get back to audit // TCHAR szFactoryPath[MAX_PATH] = NULLSTR; if ( !LockApplication(TRUE) ) { MessageBoxFromMessage( MSG_ALREADY_RUNNING, IDS_APPTITLE, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; } Audit = TRUE; FProcessSwitches(); LockApplication(FALSE); } break; case IDFACTORY: // Factory if ( !LockApplication(TRUE) ) { MessageBoxFromMessage( MSG_ALREADY_RUNNING, IDS_APPTITLE, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; } Factory = TRUE; // Prepare for factory mode // FProcessSwitches(); LockApplication(FALSE); break; // Action Flags checkboxes // case IDC_MINISETUP: SetFlag(hwnd, wParam, &bMiniSetup); // If mini-setup checkbox is set, then enable the PNP checkbox, // otherwise disable it. if ( !bMiniSetup ) { PnP = FALSE; SetCheck(hwnd, IDC_PNP, PnP); EnableWindow(GetDlgItem(hwnd, IDC_PNP), FALSE); } else { EnableWindow(GetDlgItem(hwnd, IDC_PNP), TRUE); } break; case IDC_PNP: SetFlag(hwnd, wParam, &PnP); break; case IDC_ACTIVATED: SetFlag(hwnd, wParam, &bActivated); break; case IDC_NOSIDGEN: SetFlag(hwnd, wParam, &NoSidGen); break; case IDC_SHUTDOWN: if ( CBN_SELCHANGE == HIWORD(wParam) ) { BOOL *lpbFlag; // Reset all flags to false first. // ForceShutdown = Reboot = NoReboot = FALSE; // lParam is the HWND of the ComboBox. // lpbFlag = (BOOL*) SendMessage((HWND) lParam, CB_GETITEMDATA, (SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0)), 0); // Set the flag associated with this choice. // if ( ((INT_PTR) lpbFlag != CB_ERR) && lpbFlag ) { *lpbFlag = TRUE; } } break; default: break; } break; default: break; } return FALSE; } ////////////////////////////////////////////////////////////////////////////// // Shutdown - resets the oemaudit.inf file sections and removes // HKLM\Software\Microsoft\Windows\CurrentVersion\AuditMode // BOOL FShutdown() { BOOL fReturn = TRUE; // Launch sysprep to reseal the machine // if (!(fReturn = ResealMachine())) LogFileStr(g_szLogFile, _T("SYSPREP: Shutdown could not reseal the machine!\r\n")); return fReturn; } ////////////////////////////////////////////////////////////////////////////// // FlushAndDisableRegistry - flushes registry keys // void FlushAndDisableRegistry() { RegFlushKey(HKEY_LOCAL_MACHINE); RegFlushKey(HKEY_USERS); } ////////////////////////////////////////////////////////////////////////////// // uiDialogTopRight - this was copied over from SETUPX.DLL // void uiDialogTopRight(HWND hwndDlg) { RECT rc; int cxDlg; int cxScreen = GetSystemMetrics( SM_CXSCREEN ); GetWindowRect(hwndDlg,&rc); cxDlg = rc.right - rc.left; // Position the dialog. // SetWindowPos(hwndDlg, NULL, cxScreen - cxDlg, 8, 0, 0, SWP_NOSIZE|SWP_NOZORDER); } ////////////////////////////////////////////////////////////////////////////// // ParseRegistrySwitches - checks the registry for oemreset switches // TCHAR* ParseRegistrySwitches() { static TCHAR szCmdLineArgs[MAX_PATH] = _T(""); HKEY hKey = 0; if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, &hKey) == ERROR_SUCCESS) { DWORD dwSize = MAX_PATH; RegQueryValueEx(hKey, REGSTR_VAL_OEMRESETSWITCH, 0L, NULL, (LPBYTE)szCmdLineArgs, &dwSize); RegSetValueEx(hKey, REGSTR_VAL_OEMRESETSWITCH, 0, REG_SZ, (LPBYTE)_T(""), sizeof(_T(""))); RegCloseKey(hKey); } return szCmdLineArgs; } ////////////////////////////////////////////////////////////////////////////// // ParseCmdLineSwitches - this was copied over from OPKWIZ (JCOHEN) // BOOL ParseCmdLineSwitches(LPTSTR lpszCmdLineOrg) { LPTSTR lpLine = lpszCmdLineOrg, lpArg; TCHAR szTmpBuf[MAX_PATH]; INT i; BOOL bHandled= FALSE, bError = FALSE, bLeftQ = FALSE, bRegistry = FALSE; // If we have no command line, then return // if ( lpLine == NULL ) return bHandled; // If empty command line, then try registry. // if ( *lpLine == NULLCHR ) { lpLine = ParseRegistrySwitches(); // If registry is empty then return not handled if (lpLine == NULL) return bHandled; // Registry switches don't have / or - and are separated by semi-colons bRegistry = TRUE; }; // Loop through command line. // while ( *lpLine != NULLCHR ) { // Move to first non-white TCHAR. // lpArg = lpLine; while ( isspace((int) *lpArg) ) lpArg = CharNext (lpArg); if ( *lpArg ) { // Move to next white TCHAR. // lpLine = lpArg; while ( ( *lpLine != NULLCHR ) && ( *lpLine != _T(';') ) && ( ( !bLeftQ && ( !isspace((int) *lpLine) ) ) || ( bLeftQ && ( *lpLine != _T('"') ) ) ) ) { lpLine = CharNext (lpLine); if ( !bLeftQ && (*lpLine == _T('"')) ) { lpLine = CharNext (lpLine); bLeftQ = TRUE; } } // Copy arg to buffer. // i = (INT)(lpLine - lpArg + 1); // +1 for NULL. lstrcpyn( szTmpBuf, lpArg, i ); // Skip semi-colons if (bRegistry && *lpLine == _T(';')) lpLine = CharNext(lpLine); if ( bLeftQ ) { lpLine = CharNext (lpLine); // skip the " from remander of command line. bLeftQ = FALSE; } // Command line comands starting with either '/' or '-' unless it's from // the registry if ( !bRegistry && ( *szTmpBuf != _T('/') ) && ( *szTmpBuf != _T('-') ) ) { bError = TRUE; break; } else { // Skip pass '/' or '-' if not from registry TCHAR* pszSwitch = NULL; if (!bRegistry) pszSwitch = CharNext(szTmpBuf); else pszSwitch = szTmpBuf; // Because we have switches that have multiple chars // I'm using an if/elseif otherwise I would use // switch statements // if (_tcsicmp(pszSwitch, _T("R")) == 0) gdwCmdlineFlags |= OEMRESET_AUDIT; else if ((_tcsicmp(pszSwitch, _T("AUTO")) == 0) || (_tcsicmp(pszSwitch, _T("A") ) == 0)) gdwCmdlineFlags |= OEMRESET_AUTO; else if (_tcsicmp(pszSwitch, _T("S")) == 0) gdwCmdlineFlags |= OEMRESET_SHUTDOWN; else if (_tcsicmp(pszSwitch, _T("L")) == 0) gdwCmdlineFlags |= OEMRESET_LOG; else if (_tcsicmp(pszSwitch, _T("H")) == 0) gdwCmdlineFlags |= OEMRESET_HIDE; else if (_tcsicmp(pszSwitch, _T("P")) == 0) gdwCmdlineFlags |= OEMRESET_AUDITPD; else bError = TRUE; } } else break; } // If we hit an error, display the error and show the help. // if ( bError ) { LPTSTR lpHelp = AllocateString(NULL, IDS_HELP); MsgBox(NULL, IDS_ERR_BADCMDLINE, IDS_APPNAME, MB_ERRORBOX, lpHelp ? lpHelp : NULLSTR); FREE(lpHelp); bHandled = TRUE; // Exit the app if bad command line! } return bHandled; } ////////////////////////////////////////////////////////////////////////////// // MonitorKeyValueThread - we're monitoring the OEMReset_Switch in the registry // // DWORD WINAPI MonitorKeyValueThread(LPVOID lpv) { HKEY hKey; // Open the key we want to monitor if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, &hKey) == ERROR_SUCCESS) { do { ParseCmdLineSwitches(_T("")); // empty so it checks the registry HandleCommandSwitches(); } while (ERROR_SUCCESS == RegNotifyChangeKeyValue(hKey, FALSE, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET, 0, FALSE)); RegCloseKey(hKey); } return 0; } ////////////////////////////////////////////////////////////////////////////// // Starts a thread to monitor a registry key for cmdline switches // void StartMonitorKeyValue() { ghMonitorThread = CreateThread(NULL, 0, MonitorKeyValueThread, 0, 0, &gdwThreadID); } ////////////////////////////////////////////////////////////////////////////// // Processes the cmdline switches // static void HandleCommandSwitches() { // Non-processing flags 1st if (gdwCmdlineFlags & OEMRESET_HIDE) { gbHide = TRUE; } if (gdwCmdlineFlags & OEMRESET_LOG) { gbLog = TRUE; } // Process switches precedence 2nd if (gdwCmdlineFlags & OEMRESET_SHUTDOWN) { if (FShutdown()) // cleanup ShutdownOrReboot(EWX_SHUTDOWN, SYSPREP_SHUTDOWN_FLAGS); // Powers down using Enduser Path } else if (gdwCmdlineFlags & OEMRESET_AUTO) { if (FShutdown()) // cleanup ShutdownOrReboot(EWX_REBOOT, SYSPREP_SHUTDOWN_FLAGS); // Reboots using Enduser Path } else if (gdwCmdlineFlags & OEMRESET_AUDIT) { ShutdownOrReboot(EWX_REBOOT, SYSPREP_SHUTDOWN_FLAGS); // Reboots using Audit Path } else if (gdwCmdlineFlags & OEMRESET_AUDITPD) { ShutdownOrReboot(EWX_SHUTDOWN, SYSPREP_SHUTDOWN_FLAGS); // Powers down using Audit Path } } void ShowOemresetDialog(HINSTANCE hInstance) { // First instance ghinstEXE = hInstance; // Set the error mode to avoid system error pop-ups. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); // Monitors a registry key for switches for Oemreset StartMonitorKeyValue(); // Create our modeless dialog if ((ghwndOemResetDlg = CreateOemResetDlg(hInstance)) != NULL) { MSG msg; // Hide ourself if needed and start a thread which // monitors the reg key value if (gbHide) { ShowWindow(ghwndOemResetDlg, SW_HIDE); } // Message pump while (GetMessage(&msg, NULL, 0, 0)) { if (!IsWindow(ghwndOemResetDlg) || !IsDialogMessage(ghwndOemResetDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } return; } // Make sure the user knows what he's doing with the Sids. BOOL VerifySids() { if ( RegExists(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_SIDGEN) ) { if ( RegCheck(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_SIDGEN) ) { if ( !NoSidGen ) { return ( IDOK == MessageBoxFromMessage( MSG_DONT_GEN_SIDS, IDS_APPTITLE, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL | MB_DEFBUTTON2) ); } } else { if ( NoSidGen ) { return ( IDOK == MessageBoxFromMessage( MSG_DO_GEN_SIDS, IDS_APPTITLE, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL | MB_DEFBUTTON2) ); } } } else if ( !NoSidGen ) // If sids have never been regenerated. { return ( IDOK == MessageBoxFromMessage( MSG_DONT_GEN_SIDS, IDS_APPTITLE, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_TASKMODAL | MB_DEFBUTTON2) ); } // If we fall through to here we must be ok. // return TRUE; }