Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1272 lines
38 KiB

// 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 <stdlib.h>
#include <TCHAR.h>
#include "..\Common\util.h"
#include <windowsx.h>
#include <commctrl.h>
#include <shellapi.h>
#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.
}