1188 lines
26 KiB
C
1188 lines
26 KiB
C
|
/*++
|
||
|
|
||
|
Microsoft Confidential
|
||
|
Copyright (c) 1992-1997 Microsoft Corporation
|
||
|
All rights reserved
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
crashdmp.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implements the "Recovery" group on the Startup/Recovery
|
||
|
dialog of the System Control Panel Applet
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
The virtual memory settings and the crash dump (core dump) settings
|
||
|
are tightly-coupled. Therefore, crashdmp.c and startup.h have some
|
||
|
heavy dependencies on virtual.c and virtual.h (and vice versa).
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Byron Dazey 06-Jun-1992
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
15-Oct-1997 scotthal
|
||
|
Complete overhaul
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "sysdm.h"
|
||
|
#include <windowsx.h>
|
||
|
|
||
|
#define KBYTE (1024UI64)
|
||
|
#define MBYTE (1024UI64 * KBYTE)
|
||
|
#define GBYTE (1024UI64 * MBYTE)
|
||
|
|
||
|
//
|
||
|
// CrashDumpEnabled is not a boolean value anymore. It can take on one of the
|
||
|
// following types.
|
||
|
//
|
||
|
|
||
|
#define DUMP_TYPE_NONE (0)
|
||
|
#define DUMP_TYPE_MINI (1)
|
||
|
#define DUMP_TYPE_SUMMARY (2)
|
||
|
#define DUMP_TYPE_FULL (3)
|
||
|
#define DUMP_TYPE_MAX (4)
|
||
|
|
||
|
#define REG_LOG_EVENT_VALUE_NAME TEXT ("LogEvent")
|
||
|
#define REG_SEND_ALERT_VALUE_NAME TEXT ("SendAlert")
|
||
|
#define REG_OVERWRITE_VALUE_NAME TEXT ("Overwrite")
|
||
|
#define REG_AUTOREBOOT_VALUE_NAME TEXT ("AutoReboot")
|
||
|
#define REG_DUMPFILE_VALUE_NAME TEXT ("DumpFile")
|
||
|
#define REG_MINIDUMP_DIR_VALUE_NAME TEXT ("MinidumpDir")
|
||
|
#define REG_DUMP_TYPE_VALUE_NAME TEXT ("CrashDumpEnabled")
|
||
|
|
||
|
#define BIG_MEMORY_MAX_BOOT_PF_MB (2048)
|
||
|
#define CRASH_CONTROL_KEY TEXT("System\\CurrentControlSet\\Control\\CrashControl")
|
||
|
|
||
|
//
|
||
|
// The crashdump code is hard-coded to generate only summary dumps for
|
||
|
// machines with more than 2 GB of physical memory. Do not change this
|
||
|
// constant unless unless you change the same code in ntos\io\dumpctl.c
|
||
|
//
|
||
|
|
||
|
#define LARGE_MEMORY_THRESHOLD (2 * GBYTE)
|
||
|
|
||
|
typedef struct _SYSTEM_MEMORY_CONFIGURATION {
|
||
|
BOOL BigMemory;
|
||
|
ULONG PageSize;
|
||
|
ULONG64 PhysicalMemorySize;
|
||
|
ULONG64 BootPartitionPageFileSize;
|
||
|
TCHAR BootDrive;
|
||
|
} SYSTEM_MEMORY_CONFIGURATION;
|
||
|
|
||
|
VCREG_RET gvcCrashCtrl = VCREG_ERROR;
|
||
|
HKEY ghkeyCrashCtrl = NULL;
|
||
|
int gcrefCrashCtrl = 0;
|
||
|
BOOL gfCoreDumpChanged = FALSE;
|
||
|
|
||
|
TCHAR CrashDumpFile [MAX_PATH] = TEXT("%SystemRoot%\\MEMORY.DMP");
|
||
|
TCHAR MiniDumpDirectory [MAX_PATH] = TEXT("%SystemRoot%\\Minidump");
|
||
|
TCHAR DumpFileText [100];
|
||
|
TCHAR MiniDumpDirText [100];
|
||
|
|
||
|
SYSTEM_MEMORY_CONFIGURATION SystemMemoryConfiguration;
|
||
|
|
||
|
//
|
||
|
// Private function prototypes
|
||
|
//
|
||
|
|
||
|
DWORD
|
||
|
GetDumpSelection(
|
||
|
HWND hDlg
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
GetMemoryConfiguration(
|
||
|
OUT SYSTEM_MEMORY_CONFIGURATION * MemoryConfig
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
DisableCoreDumpControls(
|
||
|
HWND hDlg
|
||
|
);
|
||
|
|
||
|
static
|
||
|
BOOL
|
||
|
CoreDumpInit(
|
||
|
IN HWND hDlg
|
||
|
);
|
||
|
|
||
|
static
|
||
|
BOOL
|
||
|
CoreDumpUpdateRegistry(
|
||
|
IN HWND hDlg,
|
||
|
IN HKEY hKey
|
||
|
);
|
||
|
|
||
|
int
|
||
|
CoreDumpHandleOk(
|
||
|
IN BOOL fInitialized,
|
||
|
IN HWND hDlg,
|
||
|
IN WPARAM wParam,
|
||
|
IN LPARAM lParam
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SwapDumpSelection(
|
||
|
HWND hDlg
|
||
|
);
|
||
|
//
|
||
|
// Implementation
|
||
|
//
|
||
|
|
||
|
VCREG_RET
|
||
|
CoreDumpOpenKey(
|
||
|
)
|
||
|
{
|
||
|
if (gvcCrashCtrl == VCREG_ERROR) {
|
||
|
gvcCrashCtrl = OpenRegKey( CRASH_CONTROL_KEY, &ghkeyCrashCtrl );
|
||
|
}
|
||
|
|
||
|
if (gvcCrashCtrl != VCREG_ERROR) {
|
||
|
gcrefCrashCtrl++;
|
||
|
}
|
||
|
|
||
|
return gvcCrashCtrl;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CoreDumpCloseKey(
|
||
|
)
|
||
|
{
|
||
|
if (gcrefCrashCtrl > 0) {
|
||
|
gcrefCrashCtrl--;
|
||
|
if (gcrefCrashCtrl == 0) {
|
||
|
CloseRegKey( ghkeyCrashCtrl );
|
||
|
gvcCrashCtrl = VCREG_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
StartAlerterService(
|
||
|
IN SC_HANDLE hAlerter
|
||
|
)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
|
||
|
fResult = ChangeServiceConfig(
|
||
|
hAlerter,
|
||
|
SERVICE_NO_CHANGE,
|
||
|
SERVICE_AUTO_START,
|
||
|
SERVICE_NO_CHANGE,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
fResult = StartService(hAlerter, 0, NULL);
|
||
|
|
||
|
return(fResult);
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
IsAlerterSvcStarted(
|
||
|
HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
SC_HANDLE schSCManager, schService = NULL;
|
||
|
LPQUERY_SERVICE_CONFIG lpqscBuf;
|
||
|
DWORD dwBytesNeeded;
|
||
|
BOOL fRunning = FALSE;
|
||
|
SERVICE_STATUS ssSrvcStat;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Open the Service Controller
|
||
|
*/
|
||
|
schSCManager = OpenSCManager(
|
||
|
NULL, /* local machine */
|
||
|
NULL, /* ServicesActive database */
|
||
|
SC_MANAGER_ALL_ACCESS); /* full access rights */
|
||
|
|
||
|
if (schSCManager == NULL) {
|
||
|
goto iassExit;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Try to open the Alerter Service
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* Open a handle to the service. */
|
||
|
|
||
|
schService = OpenService(
|
||
|
schSCManager, /* SCManager database */
|
||
|
TEXT("Alerter"), /* name of service */
|
||
|
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_START
|
||
|
);
|
||
|
|
||
|
if (schService == NULL) {
|
||
|
goto iassExit;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Query the Alerter service to see if it has been started
|
||
|
*/
|
||
|
|
||
|
if (!QueryServiceStatus(schService, &ssSrvcStat )) {
|
||
|
goto iassExit;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (ssSrvcStat.dwCurrentState != SERVICE_RUNNING) {
|
||
|
fRunning = StartAlerterService(schService);
|
||
|
} else {
|
||
|
|
||
|
fRunning = TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
iassExit:
|
||
|
if (!fRunning) {
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_NOALERTER, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION );
|
||
|
}
|
||
|
|
||
|
if (schService != NULL) {
|
||
|
CloseServiceHandle(schService);
|
||
|
}
|
||
|
|
||
|
if (schSCManager != NULL) {
|
||
|
CloseServiceHandle(schSCManager);
|
||
|
}
|
||
|
|
||
|
return fRunning;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
VerifyDumpPath(
|
||
|
IN HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
TCHAR szExpPath[MAX_PATH];
|
||
|
LPTSTR psz;
|
||
|
TCHAR ch;
|
||
|
UINT uType;
|
||
|
|
||
|
if( GetDlgItemText(hDlg, IDC_STARTUP_CDMP_FILENAME, szPath,
|
||
|
ARRAYSIZE(szPath)) == 0) {
|
||
|
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_DEBUGGING_FILENAME, IDS_SYSDM_TITLE, MB_ICONSTOP | MB_OK);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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 (ExpandEnvironmentStrings(szPath, szExpPath, ARRAYSIZE(szExpPath)) >= ARRAYSIZE(szExpPath)) {
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_DEBUGGING_PATHLONG, IDS_SYSDM_TITLE, MB_ICONSTOP | MB_OK,
|
||
|
(DWORD)MAX_PATH);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// now cannonicalize it
|
||
|
|
||
|
GetFullPathName( szExpPath, ARRAYSIZE(szPath), szPath, &psz );
|
||
|
|
||
|
// check to see that it already was cannonicalized
|
||
|
|
||
|
if (lstrcmp( szPath, szExpPath ) != 0) {
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_DEBUGGING_UNQUALIFIED, IDS_SYSDM_TITLE, MB_ICONSTOP | MB_OK );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* check the drive (don't allow remote)
|
||
|
*/
|
||
|
|
||
|
ch = szPath[3];
|
||
|
szPath[3] = TEXT('\0');
|
||
|
if (IsPathSep(szPath[0]) || ((uType = GetDriveType(szPath)) !=
|
||
|
DRIVE_FIXED && uType != DRIVE_REMOVABLE)) {
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_DEBUGGING_DRIVE, IDS_SYSDM_TITLE, MB_ICONSTOP | MB_OK );
|
||
|
return FALSE;
|
||
|
}
|
||
|
szPath[3] = ch;
|
||
|
|
||
|
/*
|
||
|
* if path is non-exstant, tell user and let him decide what to do
|
||
|
*/
|
||
|
|
||
|
if (GetFileAttributes(szPath) == 0xFFFFFFFFL && GetLastError() !=
|
||
|
ERROR_FILE_NOT_FOUND && MsgBoxParam(hDlg, IDS_SYSDM_DEBUGGING_PATH, IDS_SYSDM_TITLE,
|
||
|
MB_ICONQUESTION | MB_YESNO ) == IDYES) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CoreDumpValidFile(
|
||
|
HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
switch (GetDumpSelection (hDlg)) {
|
||
|
|
||
|
case DUMP_TYPE_NONE:
|
||
|
return TRUE;
|
||
|
|
||
|
case DUMP_TYPE_MINI:
|
||
|
return VerifyDumpPath (hDlg);
|
||
|
|
||
|
|
||
|
case DUMP_TYPE_SUMMARY:
|
||
|
case DUMP_TYPE_FULL:
|
||
|
return VerifyDumpPath (hDlg);
|
||
|
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
APIENTRY
|
||
|
CoreDumpDlgProc(
|
||
|
HWND hDlg,
|
||
|
UINT message,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
static BOOL fInitialized = FALSE;
|
||
|
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
g_fStartupInitializing = TRUE;
|
||
|
fInitialized = CoreDumpInit(hDlg);
|
||
|
g_fStartupInitializing = FALSE;
|
||
|
return RET_CONTINUE;
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
|
||
|
switch (LOWORD(wParam)) {
|
||
|
case IDOK:
|
||
|
return(CoreDumpHandleOk(fInitialized, hDlg, wParam, lParam));
|
||
|
break;
|
||
|
|
||
|
case IDCANCEL:
|
||
|
if (fInitialized) {
|
||
|
VirtualCloseKey();
|
||
|
CoreDumpCloseKey();
|
||
|
}
|
||
|
// Let the Startup/Recovery dlg proc also handle IDOK
|
||
|
return(RET_NO_CHANGE);
|
||
|
break;
|
||
|
|
||
|
case IDC_STARTUP_CDMP_TYPE: {
|
||
|
SwapDumpSelection (hDlg);
|
||
|
}
|
||
|
// Fall through
|
||
|
|
||
|
case IDC_STARTUP_CDMP_FILENAME:
|
||
|
case IDC_STARTUP_CDMP_LOG:
|
||
|
case IDC_STARTUP_CDMP_SEND:
|
||
|
case IDC_STARTUP_CDMP_OVERWRITE:
|
||
|
case IDC_STARTUP_CDMP_AUTOREBOOT:
|
||
|
if (!g_fStartupInitializing) {
|
||
|
gfCoreDumpChanged = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
default: {
|
||
|
// indicat not handled
|
||
|
return RET_CONTINUE;
|
||
|
}
|
||
|
}
|
||
|
break; // WM_COMMAND
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
return RET_CONTINUE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return RET_CONTINUE;
|
||
|
}
|
||
|
|
||
|
return RET_BREAK;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
CoreDumpHandleOk(
|
||
|
IN BOOL fInitialized,
|
||
|
IN HWND hDlg,
|
||
|
IN WPARAM wParam,
|
||
|
IN LPARAM lParam
|
||
|
)
|
||
|
{
|
||
|
BOOL fRegChg;
|
||
|
NTSTATUS Status;
|
||
|
DWORD Ret;
|
||
|
int iRet = RET_NO_CHANGE;
|
||
|
SYSTEM_MEMORY_CONFIGURATION MemoryConfig = {0};
|
||
|
|
||
|
if (fInitialized && gfCoreDumpChanged)
|
||
|
{
|
||
|
// Validate crashdump file name.
|
||
|
if (!CoreDumpValidFile(hDlg))
|
||
|
{
|
||
|
SetFocus(GetDlgItem(hDlg, IDC_STARTUP_CDMP_FILENAME));
|
||
|
SetWindowLongPtr (hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
|
||
|
iRet = RET_ERROR;
|
||
|
return iRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
Status = GetMemoryConfiguration(&MemoryConfig);
|
||
|
|
||
|
if (NT_SUCCESS (Status) &&
|
||
|
MemoryConfig.BootPartitionPageFileSize <
|
||
|
CoreDumpGetRequiredFileSize (hDlg))
|
||
|
{
|
||
|
// Warn that the dump file may be truncated.
|
||
|
Ret = MsgBoxParam (hDlg,
|
||
|
IDS_SYSDM_DEBUGGING_MINIMUM,
|
||
|
IDS_SYSDM_TITLE,
|
||
|
MB_ICONEXCLAMATION | MB_YESNO,
|
||
|
(MemoryConfig.BootDrive ? MemoryConfig.BootDrive : TEXT('?')),
|
||
|
(DWORD) (CoreDumpGetRequiredFileSize (hDlg) / MBYTE)
|
||
|
);
|
||
|
|
||
|
if (Ret == IDNO)
|
||
|
{
|
||
|
return RET_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If the Alert button is checked, make sure the alerter service
|
||
|
// is started.
|
||
|
if (IsDlgButtonChecked(hDlg, IDC_STARTUP_CDMP_SEND))
|
||
|
{
|
||
|
IsAlerterSvcStarted(hDlg);
|
||
|
}
|
||
|
|
||
|
fRegChg = CoreDumpUpdateRegistry (hDlg, ghkeyCrashCtrl);
|
||
|
|
||
|
// Clean up registry stuff
|
||
|
CoreDumpCloseKey();
|
||
|
VirtualCloseKey();
|
||
|
|
||
|
if (fRegChg)
|
||
|
{
|
||
|
// Notify the kernel to reread the crashdump parameters from the registry.
|
||
|
Status = NtSetSystemInformation(SystemCrashDumpStateInformation, NULL, 0);
|
||
|
if (NT_SUCCESS(Status))
|
||
|
{
|
||
|
iRet = RET_CHANGE_NO_REBOOT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iRet = RET_RECOVER_CHANGE;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
iRet = RET_NO_CHANGE;
|
||
|
}
|
||
|
|
||
|
return(iRet);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CoreDumpInitErrorExit(
|
||
|
HWND hDlg,
|
||
|
HKEY hk
|
||
|
)
|
||
|
{
|
||
|
MsgBoxParam(hDlg, IDS_SYSDM_NOOPEN_RECOVER_GROUP, IDS_SYSDM_TITLE, MB_ICONEXCLAMATION);
|
||
|
if( hk == ghkeyMemMgt )
|
||
|
VirtualCloseKey();
|
||
|
|
||
|
DisableCoreDumpControls(hDlg);
|
||
|
|
||
|
HourGlass(FALSE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
GetDumpSelection(
|
||
|
HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
HWND hControl;
|
||
|
|
||
|
hControl = GetDlgItem (hDlg, IDC_STARTUP_CDMP_TYPE);
|
||
|
return ComboBox_GetCurSel ( hControl );
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DisableCoreDumpControls(
|
||
|
HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_GRP), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_TXT1), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_LOG ), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_SEND), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_TYPE), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_OVERWRITE), FALSE);
|
||
|
EnableWindow( GetDlgItem (hDlg, IDC_STARTUP_CDMP_AUTOREBOOT), FALSE);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
SwapDumpSelection(
|
||
|
HWND hDlg
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// If there is no dump type, disable some controls. If this is a minidump
|
||
|
// disable overwrite and change "File Name:" to "Mini Dump Directory:"
|
||
|
//
|
||
|
|
||
|
switch (GetDumpSelection (hDlg)) {
|
||
|
|
||
|
case DUMP_TYPE_NONE:
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_OVERWRITE), FALSE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME), FALSE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL), FALSE);
|
||
|
SetWindowText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME),
|
||
|
CrashDumpFile
|
||
|
);
|
||
|
Static_SetText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL),
|
||
|
DumpFileText
|
||
|
);
|
||
|
break;
|
||
|
|
||
|
case DUMP_TYPE_MINI:
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_OVERWRITE), FALSE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME), TRUE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL), TRUE);
|
||
|
SetWindowText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME),
|
||
|
MiniDumpDirectory
|
||
|
);
|
||
|
Static_SetText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL),
|
||
|
MiniDumpDirText
|
||
|
);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_OVERWRITE), TRUE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME), TRUE);
|
||
|
EnableWindow (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL), TRUE);
|
||
|
SetWindowText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILENAME),
|
||
|
CrashDumpFile
|
||
|
);
|
||
|
Static_SetText (GetDlgItem (hDlg, IDC_STARTUP_CDMP_FILE_LABEL),
|
||
|
DumpFileText
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
GetSystemDrive(
|
||
|
OUT TCHAR * Drive
|
||
|
)
|
||
|
{
|
||
|
TCHAR WindowsDir [ MAX_PATH ];
|
||
|
|
||
|
if (!GetWindowsDirectory (WindowsDir, ARRAYSIZE (WindowsDir))) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!isalpha (*WindowsDir)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*Drive = *WindowsDir;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
GetMemoryConfiguration(
|
||
|
OUT SYSTEM_MEMORY_CONFIGURATION * MemoryConfig
|
||
|
)
|
||
|
{
|
||
|
BOOL Succ;
|
||
|
TCHAR SystemDrive;
|
||
|
NTSTATUS Status;
|
||
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
||
|
ULONGLONG iMaxPageFileSize;
|
||
|
|
||
|
Status = NtQuerySystemInformation(
|
||
|
SystemBasicInformation,
|
||
|
&BasicInfo,
|
||
|
sizeof (BasicInfo),
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (NT_SUCCESS (Status)) {
|
||
|
Status;
|
||
|
}
|
||
|
|
||
|
MemoryConfig->PhysicalMemorySize =
|
||
|
(ULONG64) BasicInfo.NumberOfPhysicalPages *
|
||
|
(ULONG64) BasicInfo.PageSize;
|
||
|
|
||
|
MemoryConfig->PageSize = BasicInfo.PageSize;
|
||
|
|
||
|
//
|
||
|
// Get the Boot-partition pagefile size.
|
||
|
//
|
||
|
|
||
|
Succ = GetSystemDrive (&SystemDrive);
|
||
|
|
||
|
if (!Succ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
MemoryConfig->BootDrive = (WCHAR) toupper (SystemDrive);
|
||
|
|
||
|
SystemDrive = tolower (SystemDrive) - 'a';
|
||
|
|
||
|
//
|
||
|
// A big memory machine is one that has more memory than we can write to
|
||
|
// at crashdump time.
|
||
|
//
|
||
|
|
||
|
iMaxPageFileSize = GetMaxPagefileSizeInMB(SystemDrive);
|
||
|
iMaxPageFileSize *= (1024 * 1024); // MaxPageFileSize stored in megabytes
|
||
|
if ((ULONGLONG)MemoryConfig->PhysicalMemorySize >= iMaxPageFileSize) {
|
||
|
MemoryConfig->BigMemory = TRUE;
|
||
|
} else {
|
||
|
MemoryConfig->BigMemory = FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NOTE: apf is a global exposed by virtual.c
|
||
|
//
|
||
|
|
||
|
Succ = VirtualGetPageFiles ( apf );
|
||
|
|
||
|
if (!Succ) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This is the file size in terms of megabytes.
|
||
|
//
|
||
|
|
||
|
MemoryConfig->BootPartitionPageFileSize = apf [ SystemDrive ].nMinFileSize;
|
||
|
|
||
|
//
|
||
|
// Convert to bytes.
|
||
|
//
|
||
|
|
||
|
MemoryConfig->BootPartitionPageFileSize *= MBYTE;
|
||
|
|
||
|
VirtualFreePageFiles ( apf );
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
CheckInitFromRegistry(
|
||
|
IN HWND hDlg,
|
||
|
IN DWORD ControlId,
|
||
|
IN HKEY RegKey,
|
||
|
IN LPTSTR ValueName,
|
||
|
IN BOOL Default
|
||
|
)
|
||
|
{
|
||
|
BOOL Succ;
|
||
|
DWORD Type;
|
||
|
DWORD Data;
|
||
|
BOOL DataSize;
|
||
|
BOOL Value;
|
||
|
|
||
|
DataSize = sizeof (Data);
|
||
|
|
||
|
Succ = RegQueryValueEx (
|
||
|
RegKey,
|
||
|
ValueName,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(LPBYTE) &Data,
|
||
|
&DataSize
|
||
|
);
|
||
|
|
||
|
if (Succ != ERROR_SUCCESS || Type != REG_DWORD) {
|
||
|
Value = Default;
|
||
|
} else {
|
||
|
Value = Data ? TRUE : FALSE;
|
||
|
}
|
||
|
|
||
|
return CheckDlgButton (hDlg, ControlId, Value);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ComboAddStringFromResource(
|
||
|
IN HWND hDlg,
|
||
|
IN DWORD ControlId,
|
||
|
IN HINSTANCE ModuleHandle,
|
||
|
IN DWORD ResourceId,
|
||
|
IN DWORD ItemData
|
||
|
)
|
||
|
{
|
||
|
DWORD Res;
|
||
|
DWORD Item;
|
||
|
HWND hControl;
|
||
|
DWORD Result;
|
||
|
WCHAR Buffer[512];
|
||
|
|
||
|
Res = LoadString(ModuleHandle, ResourceId, Buffer, ARRAYSIZE(Buffer));
|
||
|
if (Res == 0)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
hControl = GetDlgItem(hDlg, ControlId);
|
||
|
Item = ComboBox_InsertString(hControl, -1, Buffer);
|
||
|
ComboBox_SetItemData(hControl, Item, ItemData);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
StoreCheckboxToReg(
|
||
|
IN HWND hDlg,
|
||
|
IN DWORD ControlId,
|
||
|
IN HKEY hKey,
|
||
|
IN LPCTSTR RegValueName
|
||
|
)
|
||
|
{
|
||
|
DWORD Checked;
|
||
|
|
||
|
Checked = IsDlgButtonChecked (hDlg, ControlId);
|
||
|
|
||
|
RegSetValueEx(
|
||
|
hKey,
|
||
|
RegValueName,
|
||
|
0,
|
||
|
REG_DWORD,
|
||
|
(LPBYTE) &Checked,
|
||
|
sizeof (Checked)
|
||
|
);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
StoreStringToReg(
|
||
|
IN HWND hDlg,
|
||
|
IN DWORD ControlId,
|
||
|
IN HKEY hKey,
|
||
|
IN LPCTSTR RegValueName
|
||
|
)
|
||
|
{
|
||
|
TCHAR Buffer [ MAX_PATH ];
|
||
|
|
||
|
GetDlgItemText (hDlg, ControlId, Buffer, ARRAYSIZE(Buffer));
|
||
|
|
||
|
//
|
||
|
// Check the buffer for valid file-name??
|
||
|
//
|
||
|
|
||
|
RegSetValueEx (
|
||
|
hKey,
|
||
|
RegValueName,
|
||
|
0,
|
||
|
REG_EXPAND_SZ,
|
||
|
(LPBYTE) Buffer,
|
||
|
(wcslen (Buffer) + 1) * sizeof (TCHAR)
|
||
|
);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static DWORD SelectionToType [] = { 0, 3, 2, 1 };
|
||
|
|
||
|
DWORD
|
||
|
GetDumpTypeFromRegistry(
|
||
|
HKEY Key
|
||
|
)
|
||
|
{
|
||
|
DWORD DataSize;
|
||
|
DWORD Type;
|
||
|
DWORD DumpType;
|
||
|
|
||
|
DataSize = sizeof (DWORD);
|
||
|
RegQueryValueEx (
|
||
|
Key,
|
||
|
REG_DUMP_TYPE_VALUE_NAME,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(LPBYTE) &DumpType,
|
||
|
&DataSize
|
||
|
);
|
||
|
|
||
|
if (DumpType > 3) {
|
||
|
DumpType = DUMP_TYPE_MINI;
|
||
|
} else {
|
||
|
DumpType = SelectionToType [ DumpType ];
|
||
|
}
|
||
|
|
||
|
return DumpType;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CoreDumpInit(HWND hDlg)
|
||
|
{
|
||
|
BOOL Succ;
|
||
|
NTSTATUS Status;
|
||
|
DWORD DataSize;
|
||
|
DWORD DumpType;
|
||
|
DWORD Type;
|
||
|
VCREG_RET vcVirt;
|
||
|
VCREG_RET vcCore;
|
||
|
SYSTEM_MEMORY_CONFIGURATION MemoryConfig;
|
||
|
|
||
|
HourGlass (TRUE);
|
||
|
|
||
|
// Do no put anything before the initialization of the globals, here.
|
||
|
vcVirt = VirtualOpenKey();
|
||
|
|
||
|
if( vcVirt == VCREG_ERROR )
|
||
|
{
|
||
|
CoreDumpInitErrorExit(hDlg, NULL);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
vcCore = CoreDumpOpenKey();
|
||
|
if (vcCore == VCREG_ERROR)
|
||
|
{
|
||
|
CoreDumpInitErrorExit(hDlg, ghkeyMemMgt);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (vcCore == VCREG_READONLY || vcVirt == VCREG_READONLY)
|
||
|
{
|
||
|
DisableCoreDumpControls (hDlg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = GetMemoryConfiguration (&SystemMemoryConfiguration);
|
||
|
if (!NT_SUCCESS (Status))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status = GetMemoryConfiguration (&MemoryConfig);
|
||
|
if (!NT_SUCCESS (Status))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Succ = LoadString (hInstance, IDS_CRASHDUMP_DUMP_FILE, DumpFileText, ARRAYSIZE(DumpFileText));
|
||
|
Succ = LoadString (hInstance, IDS_CRASHDUMP_MINI_DIR, MiniDumpDirText, ARRAYSIZE(MiniDumpDirText));
|
||
|
|
||
|
// Special Case: Server Product does not want ability to disable logging
|
||
|
// of crashdumps.
|
||
|
if (IsWorkstationProduct ())
|
||
|
{
|
||
|
CheckInitFromRegistry(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_LOG,
|
||
|
ghkeyCrashCtrl,
|
||
|
REG_LOG_EVENT_VALUE_NAME,
|
||
|
TRUE
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CheckDlgButton (hDlg, IDC_STARTUP_CDMP_LOG, TRUE);
|
||
|
EnableWindow ( GetDlgItem (hDlg, IDC_STARTUP_CDMP_LOG), FALSE);
|
||
|
}
|
||
|
|
||
|
CheckInitFromRegistry(hDlg, IDC_STARTUP_CDMP_SEND, ghkeyCrashCtrl,REG_SEND_ALERT_VALUE_NAME, TRUE);
|
||
|
CheckInitFromRegistry(hDlg, IDC_STARTUP_CDMP_OVERWRITE, ghkeyCrashCtrl, REG_OVERWRITE_VALUE_NAME, TRUE);
|
||
|
CheckInitFromRegistry(hDlg, IDC_STARTUP_CDMP_AUTOREBOOT, ghkeyCrashCtrl, REG_AUTOREBOOT_VALUE_NAME, TRUE);
|
||
|
ComboAddStringFromResource(hDlg, IDC_STARTUP_CDMP_TYPE, hInstance, // Global hInstance
|
||
|
IDS_CRASHDUMP_NONE, 0);
|
||
|
|
||
|
#ifdef _WIN64
|
||
|
ComboAddStringFromResource(hDlg, IDC_STARTUP_CDMP_TYPE, hInstance, IDS_CRASHDUMP_MINI_WIN64, 0);
|
||
|
#else
|
||
|
ComboAddStringFromResource(hDlg, IDC_STARTUP_CDMP_TYPE, hInstance, IDS_CRASHDUMP_MINI, 0);
|
||
|
#endif
|
||
|
ComboAddStringFromResource(hDlg, IDC_STARTUP_CDMP_TYPE, hInstance, IDS_CRASHDUMP_SUMMARY, 0 );
|
||
|
|
||
|
// Special case: Server Products do not allow full memory dumps.
|
||
|
DumpType = GetDumpTypeFromRegistry(ghkeyCrashCtrl);
|
||
|
if (MemoryConfig.PhysicalMemorySize < LARGE_MEMORY_THRESHOLD)
|
||
|
{
|
||
|
ComboAddStringFromResource(hDlg, IDC_STARTUP_CDMP_TYPE, hInstance, IDS_CRASHDUMP_FULL, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (DumpType == DUMP_TYPE_FULL)
|
||
|
{
|
||
|
DumpType = DUMP_TYPE_SUMMARY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ComboBox_SetCurSel(GetDlgItem (hDlg, IDC_STARTUP_CDMP_TYPE), DumpType);
|
||
|
|
||
|
DataSize = sizeof (CrashDumpFile);
|
||
|
RegQueryValueEx (
|
||
|
ghkeyCrashCtrl,
|
||
|
REG_DUMPFILE_VALUE_NAME,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(LPBYTE) CrashDumpFile,
|
||
|
&DataSize
|
||
|
);
|
||
|
|
||
|
DataSize = sizeof (MiniDumpDirectory);
|
||
|
RegQueryValueEx (
|
||
|
ghkeyCrashCtrl,
|
||
|
REG_MINIDUMP_DIR_VALUE_NAME,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
(LPBYTE) MiniDumpDirectory,
|
||
|
&DataSize
|
||
|
);
|
||
|
|
||
|
// Update the selection fields of the dialog.
|
||
|
SwapDumpSelection (hDlg);
|
||
|
HourGlass(FALSE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CoreDumpUpdateRegistry(
|
||
|
HWND hDlg,
|
||
|
HKEY hKey
|
||
|
)
|
||
|
{
|
||
|
DWORD Selection;
|
||
|
|
||
|
StoreCheckboxToReg(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_LOG,
|
||
|
hKey,
|
||
|
REG_LOG_EVENT_VALUE_NAME
|
||
|
);
|
||
|
|
||
|
StoreCheckboxToReg(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_SEND,
|
||
|
hKey,
|
||
|
REG_SEND_ALERT_VALUE_NAME
|
||
|
);
|
||
|
|
||
|
StoreCheckboxToReg(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_OVERWRITE,
|
||
|
hKey,
|
||
|
REG_OVERWRITE_VALUE_NAME
|
||
|
);
|
||
|
|
||
|
StoreCheckboxToReg(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_AUTOREBOOT,
|
||
|
hKey,
|
||
|
REG_AUTOREBOOT_VALUE_NAME
|
||
|
);
|
||
|
|
||
|
Selection = GetDumpSelection (hDlg);
|
||
|
|
||
|
if (Selection == DUMP_TYPE_MINI) {
|
||
|
|
||
|
StoreStringToReg (
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_FILENAME,
|
||
|
hKey,
|
||
|
REG_MINIDUMP_DIR_VALUE_NAME
|
||
|
);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
StoreStringToReg(
|
||
|
hDlg,
|
||
|
IDC_STARTUP_CDMP_FILENAME,
|
||
|
hKey,
|
||
|
REG_DUMPFILE_VALUE_NAME
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (Selection > 3) {
|
||
|
Selection = 3;
|
||
|
}
|
||
|
|
||
|
Selection = SelectionToType [ Selection ];
|
||
|
RegSetValueEx (
|
||
|
hKey,
|
||
|
REG_DUMP_TYPE_VALUE_NAME,
|
||
|
0,
|
||
|
REG_DWORD,
|
||
|
(LPBYTE) &Selection,
|
||
|
sizeof (Selection)
|
||
|
);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG64
|
||
|
EstimateSummaryDumpSize(
|
||
|
ULONG64 PhysicalMemorySize
|
||
|
)
|
||
|
{
|
||
|
ULONG64 Size;
|
||
|
|
||
|
//
|
||
|
// Very rough guesses at the size of the summary dump.
|
||
|
//
|
||
|
|
||
|
if (PhysicalMemorySize < 128 * MBYTE) {
|
||
|
|
||
|
Size = 50 * MBYTE;
|
||
|
|
||
|
} else if (PhysicalMemorySize < 4 * GBYTE) {
|
||
|
|
||
|
Size = 200 * MBYTE;
|
||
|
|
||
|
} else if (PhysicalMemorySize < 8 * GBYTE) {
|
||
|
|
||
|
Size = 400 * MBYTE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Size = 800 * MBYTE;
|
||
|
}
|
||
|
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG64
|
||
|
CoreDumpGetRequiredFileSize(
|
||
|
IN HWND hDlg OPTIONAL
|
||
|
)
|
||
|
{
|
||
|
ULONG64 Size;
|
||
|
DWORD DumpType;
|
||
|
NTSTATUS Status;
|
||
|
SYSTEM_MEMORY_CONFIGURATION MemoryConfig;
|
||
|
|
||
|
|
||
|
//
|
||
|
// If we were passed a hDlg, get the selection from the dlg. Otherwise,
|
||
|
// get the selection from the registry.
|
||
|
//
|
||
|
|
||
|
if (hDlg != NULL) {
|
||
|
|
||
|
//
|
||
|
// Get selection from dlg.
|
||
|
//
|
||
|
|
||
|
DumpType = GetDumpSelection ( hDlg );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
HKEY hKey;
|
||
|
DWORD Err;
|
||
|
|
||
|
//
|
||
|
// Get selection from registry.
|
||
|
//
|
||
|
|
||
|
Err = OpenRegKey (CRASH_CONTROL_KEY,
|
||
|
&hKey
|
||
|
);
|
||
|
|
||
|
if (Err == VCREG_ERROR) {
|
||
|
return DUMP_TYPE_MINI;
|
||
|
}
|
||
|
|
||
|
ASSERT ( hKey );
|
||
|
DumpType = GetDumpTypeFromRegistry ( hKey );
|
||
|
CloseRegKey ( hKey );
|
||
|
}
|
||
|
|
||
|
switch (DumpType) {
|
||
|
|
||
|
case DUMP_TYPE_NONE:
|
||
|
Size = 0;
|
||
|
break;
|
||
|
|
||
|
case DUMP_TYPE_MINI:
|
||
|
Size = 64 * KBYTE;
|
||
|
break;
|
||
|
|
||
|
case DUMP_TYPE_SUMMARY:
|
||
|
|
||
|
Status = GetMemoryConfiguration (&MemoryConfig);
|
||
|
|
||
|
if (NT_SUCCESS (Status)) {
|
||
|
Size = EstimateSummaryDumpSize (MemoryConfig.PhysicalMemorySize);
|
||
|
} else {
|
||
|
//
|
||
|
// A (large) shot in the dark.
|
||
|
//
|
||
|
Size = 800 * MBYTE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DUMP_TYPE_FULL:
|
||
|
|
||
|
Status = GetMemoryConfiguration (&MemoryConfig);
|
||
|
|
||
|
if (NT_SUCCESS (Status)) {
|
||
|
Size = MemoryConfig.PhysicalMemorySize;
|
||
|
} else {
|
||
|
Size = 0;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT (FALSE);
|
||
|
}
|
||
|
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
|