// Copyright (c) 1997-1999 Microsoft Corporation #include "precomp.h" #ifdef EXT_DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "StartupPage.h" // avoid some warnings. #undef HDS_HORZ #undef HDS_BUTTONS #undef HDS_HIDDEN #include "resource.h" #include #include #include "..\Common\util.h" #include #include #include #include "RebootPage.h" #include "helpid.h" #include "NetUtility.h" // Reboot switch for crashdump dlg #define RET_ERROR (-1) #define RET_NO_CHANGE 0x00 #define RET_VIRTUAL_CHANGE 0x01 #define RET_RECOVER_CHANGE 0x02 #define RET_CHANGE_NO_REBOOT 0x04 #define RET_CONTINUE 0x08 #define RET_BREAK 0x10 #define RET_VIRT_AND_RECOVER (RET_VIRTUAL_CHANGE | RET_RECOVER_CHANGE) #define FORMIN 0 #define FORMAX 999 // Length of WCHAR buffer needed to hold "Display startup list for..." value #define FOR_MAX_LENGTH 20 // Default "Display startup list for..." value #define FORDEF 30 #define NO_DUMP_OPTION 0 #define COMPLETE_DUMP_OPTION 1 #define KERNEL_DUMP_OPTION 2 #define SMALL_DUMP_OPTION 3 // // Help ID's // DWORD aStartupHelpIds[] = { IDC_STARTUP_SYS_OS, (IDH_STARTUP + 0), IDC_STARTUP_SYS_ENABLECOUNTDOWN, (IDH_STARTUP + 1), IDC_STARTUP_SYS_SECONDS, (IDH_STARTUP + 2), IDC_STARTUP_SYS_SECONDS_LABEL, (IDH_STARTUP + 2), IDC_STARTUP_CDMP_TXT1, (IDH_STARTUP + 3), IDC_STARTUP_CDMP_LOG, (IDH_STARTUP + 4), IDC_STARTUP_CDMP_SEND, (IDH_STARTUP + 5), IDC_STARTUP_CDMP_FILENAME, (IDH_STARTUP + 7), IDC_STARTUP_CDMP_OVERWRITE, (IDH_STARTUP + 13), IDC_STARTUP_CDMP_AUTOREBOOT, (IDH_STARTUP + 9), IDC_STARTUP_SYSTEM_GRP, (IDH_STARTUP + 10), IDC_STARTUP_SYS_SECSCROLL, (IDH_STARTUP + 11), IDC_STARTUP_CDMP_GRP, (IDH_STARTUP + 12), IDC_STARTUP_SYSTEM_GRP2, (IDH_STARTUP + 14), IDC_STARTUP_CDMP_OPTIONS, (IDH_STARTUP + 8), IDC_EDIT_BOOT_INI_LABEL, (IDH_STARTUP + 15), IDC_EDIT_BOOT_INI, (IDH_STARTUP + 16), IDC_REBOOT, IDH_WBEM_ADVANCED_STARTRECOVER_REMOTE_REBOOT, 0, 0 }; //---------------------------------------------------------------------------- INT_PTR CALLBACK StaticStartupDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { // if this is the initDlg msg... if(message == WM_INITDIALOG) { // transfer the 'this' ptr to the extraBytes. SetWindowLongPtr(hwndDlg, DWLP_USER, lParam); } // DWL_USER is the 'this' ptr. StartupPage *me = (StartupPage *)GetWindowLongPtr(hwndDlg, DWLP_USER); if(me != NULL) { // call into the DlgProc() that has some context. return me->DlgProc(hwndDlg, message, wParam, lParam); } else { return FALSE; } } //-------------------------------------------------------------- StartupPage::StartupPage(WbemServiceThread *serviceThread) : WBEMPageHelper(serviceThread) { IWbemClassObject *pInst = NULL; m_WbemServices.SetPriv(); if((pInst = FirstInstanceOf("Win32_ComputerSystem")) != NULL) { m_computer = pInst; } if((pInst = FirstInstanceOf("Win32_OperatingSystem")) != NULL) { m_OS = pInst; } if((pInst = FirstInstanceOf("Win32_OSRecoveryConfiguration")) != NULL) { m_recovery = pInst; } if((pInst = FirstInstanceOf("Win32_LogicalMemoryConfiguration")) != NULL) { m_memory = pInst; } m_WbemServices.ClearPriv(); m_writable = TRUE; m_lBound = 1; m_bDownlevelTarget = TRUE; // Assume downlevel until proven otherwise. } //-------------------------------------------------------------- INT_PTR StartupPage::DoModal(HWND hDlg) { return DialogBoxParam(HINST_THISDLL, (LPTSTR) MAKEINTRESOURCE(IDD_STARTUP), hDlg, StaticStartupDlgProc, (LPARAM)this); } //-------------------------------------------------------------- StartupPage::~StartupPage() { } //-------------------------------------------------------------- BOOL StartupPage::CheckVal( HWND hDlg, WORD wID, WORD wMin, WORD wMax, WORD wMsgID ) { WORD nVal; BOOL bOK; HWND hVal; WCHAR szTemp[FOR_MAX_LENGTH]; if( wMin > wMax ) { nVal = wMin; wMin = wMax; wMax = nVal; } nVal = (WORD) GetDlgItemInt( hDlg, wID, &bOK, FALSE ); // // This is a hack to make the null string act equivalent to zero // if (!bOK) { bOK = !GetDlgItemTextW( hDlg, wID, szTemp, FOR_MAX_LENGTH ); } if( !bOK || ( nVal < wMin ) || ( nVal > wMax ) ) { TCHAR megBuf[30] = {0}; MsgBoxParam( hDlg, wMsgID, IDS_DISPLAY_NAME, MB_OK | MB_ICONERROR); SendMessage( hDlg, WM_NEXTDLGCTL, (WPARAM) ( hVal = GetDlgItem( hDlg, wID ) ), 1L ); // SendMessage(hVal, EM_SETSEL, NULL, MAKELONG(0, 32767)); SendMessage( hVal, EM_SETSEL, 0, 32767 ); return( FALSE ); } return( TRUE ); } //-------------------------------------------------------------- INT_PTR CALLBACK StartupPage::DlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { m_hDlg = hwndDlg; switch (message) { case WM_INITDIALOG: Init(hwndDlg); break; case WM_COMMAND: switch(HIWORD(wParam)) { case EN_CHANGE: case BN_CLICKED: case CBN_SELCHANGE: PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } switch(LOWORD(wParam)) { case IDC_STARTUP_SYS_ENABLECOUNTDOWN: if (HIWORD(wParam) == BN_CLICKED) { BOOL bChecking = (WORD) !IsDlgButtonChecked(m_hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN); CheckDlgButton(m_hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN, bChecking); EnableWindow(GetDlgItem(m_hDlg, IDC_STARTUP_SYS_SECONDS), bChecking); EnableWindow(GetDlgItem(m_hDlg, IDC_STARTUP_SYS_SECSCROLL), bChecking); if(bChecking) { Edit_SetText(GetDlgItem(m_hDlg, IDC_STARTUP_SYS_SECONDS), _T("30")); } else //unchecking it. { Edit_SetText(GetDlgItem(m_hDlg, IDC_STARTUP_SYS_SECONDS), _T("0")); } SendMessage((HWND) lParam, EM_SETSEL, 0, -1); } break; case IDC_STARTUP_SYS_SECONDS: if(HIWORD(wParam) == EN_UPDATE) { if(!CheckVal(m_hDlg, IDC_STARTUP_SYS_SECONDS, FORMIN, FORMAX, SYSTEM+4)) { SetDlgItemInt(m_hDlg, IDC_STARTUP_SYS_SECONDS, FORDEF, FALSE); SendMessage((HWND) lParam, EM_SETSEL, 0, -1); } // endif (!CheckVal() } // endif break; case IDC_REBOOT: if(HIWORD(wParam) == BN_CLICKED) { RebootPage dlg(m_serviceThread); if(dlg.DoModal(hwndDlg) == IDOK) { EnableWindow(GetDlgItem(hwndDlg, IDC_REBOOT), FALSE); m_serviceThread->DisconnectServer(); EndDialog(m_hDlg, CLOSE_SNAPIN); } } break; case IDOK: if(HIWORD(wParam) == BN_CLICKED) { if(Save()) { EndDialog(m_hDlg, IDOK); } } break; case IDCANCEL: EndDialog(m_hDlg, IDCANCEL); break; case IDC_STARTUP_CDMP_OPTIONS: OnCDMPOptionUpdate(); break; case IDC_EDIT_BOOT_INI: if (m_serviceThread && m_serviceThread->LocalConnection()) { // // Local-only option. The button has been disabled but // perform this anyway. // OnBootEdit(); } break; } break; case WM_HELP: // F1 ::WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, L"sysdm.hlp", HELP_WM_HELP, (ULONG_PTR)(LPSTR)aStartupHelpIds); break; case WM_CONTEXTMENU: // right mouse click WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR) aStartupHelpIds); break; default: return FALSE; } return TRUE; } //-------------------------------------------------------------- void StartupPage::OnCDMPOptionUpdate(void) { HWND ComboHwnd = GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OPTIONS); DWORD dwDumpOption = ComboBox_GetCurSel(ComboHwnd); EnableWindow(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_FILENAME), dwDumpOption != NO_DUMP_OPTION); EnableWindow(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OVERWRITE), dwDumpOption != NO_DUMP_OPTION); bstr_t debugPath; if (dwDumpOption == SMALL_DUMP_OPTION) { debugPath = m_recovery.GetString("MiniDumpDirectory"); } else { debugPath = m_recovery.GetString("DebugFilePath"); } Edit_SetText(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_FILENAME), debugPath); } //-------------------------------------------------------------- #define BOOT_INI _T("boot.ini") void StartupPage::OnBootEdit(void) { HKEY hReg; if (RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"), &hReg) == ERROR_SUCCESS) { TCHAR szBootDir[4]; DWORD dwType = REG_SZ; DWORD cbBootDir = sizeof(szBootDir); if (RegQueryValueEx(hReg, _T("BootDir"), NULL, &dwType, (LPBYTE)szBootDir, &cbBootDir) == ERROR_SUCCESS) { if (dwType == REG_SZ) { TCHAR szBootIni[ARRAYSIZE(szBootDir) + ARRAYSIZE(BOOT_INI)]; lstrcpy(szBootIni, szBootDir); lstrcat(szBootIni, BOOT_INI); ShellExecute(m_hDlg, NULL, // Default verb. szBootIni, // boot.ini path. NULL, // No parameters. NULL, // Default working dir. SW_SHOWNORMAL); } } RegCloseKey(hReg); } } //-------------------------------------------------------------- #define ONE_MEG 1048576 long StartupPage::GetRAMSizeMB(void) { IWbemClassObject *pInst = NULL; CWbemClassObject memory; long RAMsize = 0; if((pInst = FirstInstanceOf("Win32_LogicalMemoryConfiguration")) != NULL) { memory = pInst; long dwTotalPhys = memory.GetLong("TotalPhysicalMemory"); RAMsize = (dwTotalPhys / ONE_MEG) + 1; } return RAMsize; } //-------------------------------------------------------------- bool StartupPage::IsWorkstationProduct() { bool retval = true; bstr_t name = m_OS.GetString("Name"); if(name.length() > 0) { TCHAR sName[200] = {0}; wcscpy(sName, name); if(wcsstr(sName, L"Server") != NULL) { retval = false; } } return retval; } //-------------------------------------------------------------- TCHAR szCrashKey[] = TEXT("System\\CurrentControlSet\\Control\\CrashControl"); void StartupPage::Init(HWND hDlg) { HWND ComboHwnd; variant_t array; DWORD dwDebugInfoType; // load the startup combobox. // // Must enable SE_SYSTEM_ENVIRONMENT_NAME privilege on ia64. // #if defined(_IA64_) m_WbemServices.SetPriv(); #endif // IA64 m_computer.Get("SystemStartupOptions", (variant_t &)array); #if defined(_IA64_) m_WbemServices.ClearPriv(); #endif // IA64 if(array.vt & VT_ARRAY) { SAFEARRAY *startupArray = V_ARRAY(&array); long uBound = 1; BSTR temp; ComboHwnd = GetDlgItem(hDlg, IDC_STARTUP_SYS_OS); SafeArrayGetLBound(startupArray, 1, &m_lBound); SafeArrayGetUBound(startupArray, 1, &uBound); for (long i = m_lBound; i <= uBound; i++) { SafeArrayGetElement(startupArray, &i, &temp); ComboBox_AddString(ComboHwnd, temp); } // the first one is the selection we want (watch out for 'lBound' values) long idx = m_computer.GetLong("SystemStartupSetting"); ComboBox_SetCurSel(ComboHwnd, idx - m_lBound); // 3 chars in the second's edit box. Edit_LimitText(GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS), 3); // limit spinner to 0 - 999. SendDlgItemMessage (hDlg, IDC_STARTUP_SYS_SECSCROLL, UDM_SETRANGE, 0, (LPARAM)MAKELONG(999,0)); WCHAR buf[30] = {0}; m_delay = 0; m_delay = (short)m_computer.GetLong("SystemStartupDelay"); BOOL bChecked = (m_delay != 0); CheckDlgButton(m_hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN, bChecked); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_SECONDS), bChecked); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_SECSCROLL), bChecked); Edit_SetText(GetDlgItem(hDlg, IDC_STARTUP_SYS_SECONDS), _itow(m_delay, buf, 10)); } if( !(array.vt & VT_ARRAY) || !IsCurrentUserAdministrator()) { EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_OS), FALSE); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_ENABLECOUNTDOWN), FALSE); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_SECSCROLL), FALSE); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_SECONDS), FALSE); EnableWindow(GetDlgItem (m_hDlg, IDC_STARTUP_SYS_SECONDS_LABEL), FALSE); } // endif VT_ARRAY failure. // set all the recovery controls. // Special Case: Server Product does not want ability to disable logging // of crashdumps. WPARAM checkState; if(IsWorkstationProduct() == true) { checkState = (m_recovery.GetBool("WriteToSystemLog") ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hDlg, IDC_STARTUP_CDMP_LOG), checkState); } else { Button_SetCheck(GetDlgItem(hDlg, IDC_STARTUP_CDMP_LOG), BST_CHECKED); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_LOG),FALSE); } // // Load the dump options combo box. // dwDebugInfoType = GetDebugInfoType(); TCHAR szBuf[MAX_PATH]; // The largest string loaded here is 24 chars. szBuf[0] = _T('\0'); ComboHwnd = GetDlgItem(hDlg, IDC_STARTUP_CDMP_OPTIONS); LoadString(HINST_THISDLL, IDS_NO_DUMP, szBuf, sizeof(szBuf) / sizeof(TCHAR)); ComboBox_AddString(ComboHwnd, szBuf); szBuf[0] = _T('\0'); LoadString(HINST_THISDLL, IDS_COMPLETE_DUMP, szBuf, sizeof(szBuf) / sizeof(TCHAR)); ComboBox_AddString(ComboHwnd, szBuf); szBuf[0] = _T('\0'); LoadString(HINST_THISDLL, IDS_KERNEL_DUMP, szBuf, sizeof(szBuf) / sizeof(TCHAR)); ComboBox_AddString(ComboHwnd, szBuf); if (!m_bDownlevelTarget) { szBuf[0] = _T('\0'); LoadString(HINST_THISDLL, IDS_SMALL_DUMP, szBuf, sizeof(szBuf) / sizeof(TCHAR)); ComboBox_AddString(ComboHwnd, szBuf); } ComboBox_SetCurSel(ComboHwnd, dwDebugInfoType); checkState = (m_recovery.GetBool("SendAdminAlert") ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hDlg, IDC_STARTUP_CDMP_SEND), checkState); bstr_t debugPath; if (dwDebugInfoType == SMALL_DUMP_OPTION) { debugPath = m_recovery.GetString("MiniDumpDirectory"); } else { debugPath = m_recovery.GetString("DebugFilePath"); } Edit_SetText(GetDlgItem(hDlg, IDC_STARTUP_CDMP_FILENAME), debugPath); checkState = (m_recovery.GetBool("OverwriteExistingDebugFile") ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hDlg, IDC_STARTUP_CDMP_OVERWRITE), checkState); checkState = (m_recovery.GetBool("AutoReboot") ? BST_CHECKED : BST_UNCHECKED); Button_SetCheck(GetDlgItem(hDlg, IDC_STARTUP_CDMP_AUTOREBOOT), checkState); // // Special case disable the overwrite and logfile controls if no debug // info option specified. // EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_FILENAME), dwDebugInfoType != NO_DUMP_OPTION); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_OVERWRITE), dwDebugInfoType != NO_DUMP_OPTION); // // Test to determine if the user is an admin. // RemoteRegWriteable(szCrashKey, m_writable); if (!m_writable) { // Non-admin - disable controls. // EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_LOG ), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_SEND ), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_FILENAME), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_OVERWRITE), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_OPTIONS), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_STARTUP_CDMP_AUTOREBOOT), FALSE); } BOOL hasPriv = true, hasMethExecute = false; if(m_serviceThread && m_serviceThread->LocalConnection()) { hasPriv = HasPriv(SE_SHUTDOWN_NAME); } hasMethExecute = HasPerm(WBEM_METHOD_EXECUTE); // // Enable the edit button for local-only. // Disable boot options label and edit button on i64. // #if defined(_IA64_) EnableWindow(GetDlgItem (m_hDlg, IDC_EDIT_BOOT_INI), FALSE); EnableWindow(GetDlgItem (m_hDlg, IDC_EDIT_BOOT_INI_LABEL), FALSE); #else EnableWindow(GetDlgItem (m_hDlg, IDC_EDIT_BOOT_INI_LABEL), m_writable ? (m_serviceThread && m_serviceThread->LocalConnection()) : FALSE); EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BOOT_INI), m_writable ? (m_serviceThread && m_serviceThread->LocalConnection()) : FALSE); #endif // IA64 EnableWindow(GetDlgItem(hDlg, IDC_REBOOT), m_writable ? (hasPriv && hasMethExecute) : FALSE); } //---------------------------------------------------------------------------- DWORD StartupPage::GetDebugInfoType(void) { // NB: Whistler on, the win32 provider supports new DebugInfoType // (none,complete,kernel,small) and MiniDumpDirectory properties. // Logic is needed to compensate for downlevel machines. // // *Important note* The small dump option cannot be supported // on Win2K since the provider doesn't. // DWORD dwDebugInfoType = 0; if (FAILED(m_recovery.Get("DebugInfoType", (long&)dwDebugInfoType))) { // Downlevel or error case. // if (!m_bDownlevelTarget) { // Bail. We've previously established this isn't downlevel // but now fail to read the property. // return NO_DUMP_OPTION; } m_bDownlevelTarget = TRUE; bool bWriteDebugInfo = FALSE; if (FAILED(m_recovery.Get("WriteDebugInfo", bWriteDebugInfo))) { // Now we're clueless; default to (none). // bWriteDebugInfo = FALSE; dwDebugInfoType = NO_DUMP_OPTION; } if (bWriteDebugInfo) { bool bKernelDumpOnly; if (FAILED(m_recovery.Get("KernelDumpOnly", bKernelDumpOnly))) { // If we fail to get KernelDumpOnly we must assume complete, // since they've elected to write debugging info. // bKernelDumpOnly = FALSE; } if (bKernelDumpOnly) { dwDebugInfoType = KERNEL_DUMP_OPTION; } else { dwDebugInfoType = COMPLETE_DUMP_OPTION; } } } else { m_bDownlevelTarget = FALSE; } return dwDebugInfoType; } //---------------------------------------------------------------------------- HRESULT StartupPage::PutDebugInfoType(DWORD dwDebugInfoType) { HRESULT hr; if (m_bDownlevelTarget) { switch (dwDebugInfoType) // Intentionally verbose - compiler will // optimize. { case NO_DUMP_OPTION: hr = m_recovery.Put("WriteDebugInfo", (bool)FALSE); break; case COMPLETE_DUMP_OPTION: hr = m_recovery.Put("WriteDebugInfo", (bool)TRUE); if (SUCCEEDED(hr)) { hr = m_recovery.Put("KernelDumpOnly", (bool)FALSE); } break; case KERNEL_DUMP_OPTION: hr = m_recovery.Put("WriteDebugInfo", (bool)TRUE); if (SUCCEEDED(hr)) { hr = m_recovery.Put("KernelDumpOnly", (bool)TRUE); } break; case SMALL_DUMP_OPTION: ATLASSERT(!"Downlevel small dump option!"); hr = E_FAIL; break; default: ATLASSERT(!"Downlevel unknown dump option!"); hr = E_FAIL; } } else { hr = m_recovery.Put("DebugInfoType", (long)dwDebugInfoType); } return hr; } //---------------------------------------------------------------------------- #define MIN_SWAPSIZE 2 // Min swap file size. int StartupPage::CoreDumpHandleOk(HWND hDlg) { DWORD requiredFileSize = 0; int iRet = RET_NO_CHANGE; // Validate core dump filename if(!CoreDumpValidFile(hDlg)) { SetFocus(GetDlgItem(hDlg, IDC_STARTUP_CDMP_FILENAME)); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); iRet = RET_ERROR; return(iRet); } // If we are to write the dump file, it must be >= sizeof // phyical memory. // writing debug info? HWND ComboHwnd = GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OPTIONS); if (ComboBox_GetCurSel(ComboHwnd) != NO_DUMP_OPTION) { // go figure my pagefile requirements. requiredFileSize = ((DWORD)m_memory.GetLong("TotalPhysicalMemory") / 1024) + 1; } else if(IsDlgButtonChecked(hDlg, IDC_STARTUP_CDMP_LOG) || IsDlgButtonChecked(hDlg, IDC_STARTUP_CDMP_SEND)) { // I'll need this much to write a reminder to myself to send an // alert or write to event log once I come back up. requiredFileSize = MIN_SWAPSIZE; } // size of swapfile on the boot partition. TCHAR bootDrv[4] = {0}; DWORD bootPartitionPageFileSize = GetPageFileSize(bootDrv); // is it too small? if(bootPartitionPageFileSize < requiredFileSize) { DWORD Ret; TCHAR szTemp[30] = {0}; // Warn that the dump file may be truncated. Ret = MsgBoxParam(hDlg, SYSTEM + 29, IDS_TITLE, MB_ICONEXCLAMATION | MB_YESNO, bootDrv, _itow(requiredFileSize, szTemp, 10)); if(Ret == IDNO) { return RET_ERROR; } } return(iRet); } //---------------------------------------------------------------------------- BOOL StartupPage::CoreDumpValidFile(HWND hDlg) { TCHAR szInputPath[MAX_PATH] = {0}; TCHAR * pszPath = NULL; HWND ComboHwnd; ComboHwnd = GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OPTIONS); if (ComboBox_GetCurSel(ComboHwnd) != NO_DUMP_OPTION) { /* * get the filename */ if(GetDlgItemText(hDlg, IDC_STARTUP_CDMP_FILENAME, szInputPath, ARRAYSIZE(szInputPath)) == 0) { //ERR: enter a filename for the dumpfile. MsgBoxParam(hDlg, SYSTEM+30, IDS_DISPLAY_NAME, MB_ICONSTOP | MB_OK); return FALSE; } // // For local paths only, confirm/validate the path. Remote validation // can be done later - too complicated, if not possible in the // Whistler timeframe. // if (m_serviceThread != NULL && m_serviceThread->LocalConnection()) { /* * Expand any environment vars, and then check to make sure it * is a fully quallified path */ // if it has a '%' in it, then try to expand it if (_tcschr(szInputPath, _T('%')) != NULL) { TCHAR szExpandedPath[MAX_PATH] = {0}; DWORD cExpanded; cExpanded = ExpandEnvironmentStrings(szInputPath, szExpandedPath, sizeof(szExpandedPath) / sizeof(TCHAR)); if (cExpanded == 0 || _tcschr(szExpandedPath, _T('%')) != NULL) { // // Environment variable name(s) undefined or an error // occurred during replacement. // MsgBoxParam(hDlg, SYSTEM+40, IDS_DISPLAY_NAME, MB_ICONSTOP | MB_OK ); return FALSE; } else if (cExpanded > (sizeof(szExpandedPath) / sizeof(TCHAR))) { TCHAR buf[10]; MsgBoxParam(hDlg, SYSTEM+33, IDS_DISPLAY_NAME, MB_ICONSTOP | MB_OK, _ltow((DWORD)MAX_PATH, buf, 10)); return FALSE; } else { pszPath = szExpandedPath; } } else { pszPath = szInputPath; } // check to see that it already was cannonicalized TCHAR drv[_MAX_DRIVE] = {0}; TCHAR path[_MAX_PATH] = {0}; TCHAR fname[_MAX_FNAME] = {0}; // build the instance path. _wsplitpath(pszPath, drv, path, fname, NULL); if((_tcslen(drv) == 0) || (_tcslen(path) == 0) || (_tcslen(fname) == 0) ) { // ERR: must be a full path. MsgBoxParam(hDlg, SYSTEM+34, IDS_DISPLAY_NAME, MB_ICONSTOP | MB_OK ); return FALSE; } /* * check the drive (don't allow remote) */ if(!LocalDrive(pszPath)) { // ERR: Local drives only MsgBoxParam(hDlg, SYSTEM+31, IDS_DISPLAY_NAME, MB_ICONSTOP | MB_OK ); return FALSE; } /* * if path is non-existent, tell user and let him decide what to * do */ if(!DirExists(pszPath)) { if(MsgBoxParam(hDlg, SYSTEM+32, IDS_DISPLAY_NAME, MB_ICONQUESTION | MB_YESNO ) == IDNO) { return FALSE; } } } } return TRUE; } //---------------------------------------------------------------------------- DWORD StartupPage::GetPageFileSize(LPTSTR bootDrv) { IWbemClassObject *pInst = NULL; CWbemClassObject OS; bstr_t path; DWORD cMegBootPF = 0; TCHAR szBootPath[_MAX_PATH] = {0}; szBootPath[0] = 0; if(m_OS) { // WATCH: what's the value if GetWindowsDirectory fails? path = m_OS.GetString("WindowsDirectory"); if(path.length()) { // build the instance path. _tcscpy(szBootPath, _T("Win32_PageFileSetting=\"")); _tcsncat(szBootPath, path, 3); _tcscat(szBootPath, _T("\\pagefile.sys\"")); // while we're here.... _tcsncpy(bootDrv, path, 3); m_page = m_WbemServices.GetObject(szBootPath); if(m_page) { // NOTE: We'll need this later to change the swapfile size. /* long dwTotalPhys = m_page.GetLong("Size"); cMegBootPF = (dwTotalPhys / ONE_MEG) + 1;*/ long dwMinPageFileSize = m_page.GetLong("InitialSize"); cMegBootPF = dwMinPageFileSize; } } } return cMegBootPF; } //------------------------------------------------------------- BOOL StartupPage::ExpandRemoteEnvPath(LPTSTR szPath, LPTSTR expPath, UINT size) { //TODO: really expand the vars. _tcscpy(szPath, expPath); return TRUE; } //------------------------------------------------------------- BOOL StartupPage::LocalDrive(LPCTSTR szPath) { CWbemClassObject drive; TCHAR ltr[_MAX_PATH] = {0}; long type = 0; BOOL retval = FALSE; __int64 free = 0; // build the instance path. _tcscpy(ltr, _T("win32_LogicalDisk=\"")); _tcsncat(ltr, szPath, 2); _tcscat(ltr, _T("\"")); // save the drive letter for msgs. _tcsncpy(m_DriveLtr, szPath, 2); drive = m_WbemServices.GetObject(ltr); if(drive) { type = drive.GetLong("DriveType"); retval = ((type == DRIVE_REMOVABLE) || (type == DRIVE_FIXED)); // WARNING: this is only here cuz the LocalDrive check happens // to come before the freespace check and I didn't want to do // another GetObject() over a potentially slow network. free = drive.GetI64("FreeSpace"); m_freeSpace = (DWORD)(free / ONE_MEG); } return retval; } //------------------------------------------------------------- BOOL StartupPage::DirExists(LPCTSTR szPath) { BOOL exists = TRUE; CWbemClassObject drive; TCHAR objPath[_MAX_PATH] = {0}, drv[_MAX_DRIVE] = {0}, path[_MAX_PATH] = {0}; // build the instance path. _wsplitpath(szPath, drv, path, NULL, NULL); path[_tcslen(path) - 1] = _T('\0'); _tcscpy(objPath, _T("Win32_Directory=\"")); _tcscat(objPath, drv); // double the whacks cuz wmi has bad syntax. TCHAR cooked[_MAX_PATH] = {0}; TCHAR input[_MAX_PATH] = {0}; int len = _tcslen(path); _tcscpy(input, path); for(int x = 0; x < len; x++) { _tcsncat(cooked, &input[x], 1); // if its a whack... if(input[x] == _T('\\')) { // have another pleeb. _tcscat(cooked, _T("\\")); } } //endfor _tcscat(objPath, cooked); _tcscat(objPath, _T("\"")); drive = m_WbemServices.GetObject(objPath); exists = (drive.IsNull() ? FALSE : TRUE); return exists; } //------------------------------------------------------------- BOOL StartupPage::IsAlerterSvcStarted(HWND hDlg) { CWbemClassObject service; bool started = false; service = m_WbemServices.GetObject(_T("win32_Service=\"Alerter\"")); if(service) { started = service.GetBool("started"); if(!started) { // get the method signature. dummy wont actually be used. CWbemClassObject paramCls, inSig, dummy, outSig; // need to class def to get the method signature. paramCls = m_WbemServices.GetObject("win32_Service"); if(paramCls) { HRESULT hr = paramCls.GetMethod(L"ChangeStartMode", inSig, outSig); // if got a good signature.... if((bool)inSig) { bstr_t path = service.GetString(_T("__PATH")); inSig.Put(L"StartMode", (const _bstr_t&) L"Automatic"); // make sure the service starts on bootup. hr = m_WbemServices.ExecMethod(path, L"ChangeStartMode", inSig, outSig); // did it work? if(SUCCEEDED(hr) && (bool)outSig) { // NOTE: this guy return STATUS codes. DWORD autoStart = outSig.GetLong(L"ReturnValue"); if(autoStart == 0) { // now actually start the service. outSig = (IWbemClassObject *)0; // now call the method. hr = m_WbemServices.ExecMethod(path, L"StartService", dummy, outSig); // did the caller want the ReturnValue. if(SUCCEEDED(hr) && (bool)outSig) { // NOTE: this guy return STATUS codes. DWORD rv = outSig.GetLong(L"ReturnValue"); started = ((rv == 0) ? true : false); } } //endif autoStart } //endif SUCCEEDED() execmMethod } //endif (bool)inSig } //endif paramCls } //endif !started if(!started) { MsgBoxParam(hDlg, SYSTEM+35, IDS_DISPLAY_NAME, MB_ICONEXCLAMATION ); } } return started; } //------------------------------------------------------------- bool StartupPage::Save(void) { HRESULT hr; HWND ComboHwnd; // if its writeable-- do the work. if(m_writable) { bool computerDirty = false, recoveryDirty = false; variant_t array; SAFEARRAY *startupArray = NULL; VARTYPE varType = VT_ARRAY; ComboHwnd = GetDlgItem(m_hDlg, IDC_STARTUP_SYS_OS); // see if the selection changed (watch out for 'lBound' values) long oldIdx = m_computer.GetLong("SystemStartupSetting"); long newIdx = ComboBox_GetCurSel(ComboHwnd) + m_lBound; if(oldIdx != newIdx) { hr = m_computer.Put("SystemStartupSetting", variant_t((BYTE)newIdx)); computerDirty = true; } // see if the delay changed. WCHAR oldBuf[30], newBuf[30]; short delay = (short)m_computer.GetLong("SystemStartupDelay"); _ltow(delay, oldBuf, 10); Edit_GetText(GetDlgItem(m_hDlg, IDC_STARTUP_SYS_SECONDS), newBuf, 30); if(wcscmp(oldBuf, newBuf) != 0) { short newVal = (short)_wtol(newBuf); hr = m_computer.Put("SystemStartupDelay", variant_t(newVal)); computerDirty = true; } // evaluate all the recovery controls. WPARAM oldCheckState = (m_recovery.GetBool("WriteToSystemLog") ? BST_CHECKED : BST_UNCHECKED); WPARAM newCheckState = Button_GetCheck(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_LOG)); if(oldCheckState != newCheckState) { m_recovery.Put("WriteToSystemLog", (newCheckState == BST_CHECKED? true : false)); recoveryDirty = true; } oldCheckState = (m_recovery.GetBool("SendAdminAlert") ? BST_CHECKED : BST_UNCHECKED); newCheckState = Button_GetCheck(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_SEND)); // did the state change? if(oldCheckState != newCheckState) { m_recovery.Put("SendAdminAlert", (newCheckState == BST_CHECKED? true : false)); recoveryDirty = true; // turning ON if(newCheckState == TRUE) { // NOTE: had to move this fragment up to avoid being trapped under the wcsicmp() condition. // If the Alert button is checked, make sure the alerter service is started. IsAlerterSvcStarted(m_hDlg); } } ComboHwnd = GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OPTIONS); DWORD dwOldDebugInfoType = GetDebugInfoType(); DWORD dwNewDebugInfoType = ComboBox_GetCurSel(ComboHwnd); if (dwOldDebugInfoType != dwNewDebugInfoType) { // I detest this code. You add a member with a return code yet // nothing here checks them. At least keep the recover dirty // flag from being set and don't set the modify bit on the // filename edit control if the put fails. // hr = PutDebugInfoType(dwNewDebugInfoType); if (SUCCEEDED(hr)) { recoveryDirty = true; Edit_SetModify(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_FILENAME), TRUE); } } // // Only bother with these if other than "none" debug options is // specified. // if (dwNewDebugInfoType != NO_DUMP_OPTION) { oldCheckState = (m_recovery.GetBool("OverwriteExistingDebugFile") ? BST_CHECKED : BST_UNCHECKED); newCheckState = Button_GetCheck(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_OVERWRITE)); if(oldCheckState != newCheckState) { m_recovery.Put("OverwriteExistingDebugFile", (newCheckState == BST_CHECKED? true : false)); recoveryDirty = true; } bstr_t oldDebugPath = m_recovery.GetString( (dwOldDebugInfoType == SMALL_DUMP_OPTION) ? "MiniDumpDirectory" : "DebugFilePath"); TCHAR newDebugPath[MAX_PATH]; Edit_GetText(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_FILENAME), newDebugPath, sizeof(newDebugPath) / sizeof(TCHAR)); if(_tcsicmp(oldDebugPath,newDebugPath) != 0) { if(RET_ERROR != CoreDumpHandleOk(m_hDlg)) { m_recovery.Put( (dwNewDebugInfoType == SMALL_DUMP_OPTION) ? "MiniDumpDirectory" : "DebugFilePath", (bstr_t)newDebugPath); recoveryDirty = true; } else { long wl = GetWindowLongPtr(m_hDlg, DWLP_MSGRESULT); if(wl == PSNRET_INVALID_NOCHANGEPAGE) { return false; } } } } //endif 'WriteDebugInfo' oldCheckState = (m_recovery.GetBool("AutoReboot") ? BST_CHECKED : BST_UNCHECKED); newCheckState = Button_GetCheck(GetDlgItem(m_hDlg, IDC_STARTUP_CDMP_AUTOREBOOT)); if(oldCheckState != newCheckState) { m_recovery.Put("AutoReboot", (newCheckState == BST_CHECKED? true : false)); recoveryDirty = true; } m_WbemServices.SetPriv(); // who needs to be written? if(computerDirty) { hr = m_WbemServices.PutInstance(m_computer); } if(recoveryDirty) { // // Apparently recovery options don't require reboot in Whistler... // /* g_fRebootRequired = TRUE; MsgBoxParam(m_hDlg, SYSTEM + 39, IDS_TITLE, MB_OK | MB_ICONINFORMATION); */ hr = m_WbemServices.PutInstance(m_recovery); } m_WbemServices.ClearPriv(); } //endif m_writable return true; // close the dialog. }