Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1608 lines
51 KiB

/**************************** Module Header ********************************\
* Module Name: harderr.c
*
* Copyright 1985-91, Microsoft Corporation
*
* Hard error handler
*
* History:
* 07-03-91 JimA Created scaffolding.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "ntlpcapi.h"
HANDLE NtDllHandle = NULL;
HANDLE EventSource;
DWORD HardErrorReportMode;
UINT wIcons[] = {
0,
MB_ICONINFORMATION,
MB_ICONEXCLAMATION,
MB_ICONSTOP };
UINT wOptions[] = {
MB_ABORTRETRYIGNORE,
MB_OK,
MB_OKCANCEL,
MB_RETRYCANCEL,
MB_YESNO,
MB_YESNOCANCEL
};
DWORD dwResponses[] = {
ResponseNotHandled, // MessageBox error
ResponseOk, // IDOK
ResponseCancel, // IDCANCEL
ResponseAbort, // IDABORT
ResponseRetry, // IDRETRY
ResponseIgnore, // IDIGNORE
ResponseYes, // IDYES
ResponseNo // IDNO
};
DWORD dwResponseDefault[] = {
ResponseAbort, // OptionAbortRetryIgnore
ResponseOk, // OptionOK
ResponseOk, // OptionOKCancel
ResponseCancel, // OptionRetryCancel
ResponseYes, // OptionYes
ResponseYes, // OptionYesNoCancel
ResponseOk, // OptionShutdownSystem
};
WCHAR HardErrorachStatus[4096];
CHAR HEAnsiBuf[3072];
DWORD DisplayVDMHardError(LPDWORD ParameterVector);
LONG WOWSysErrorBoxDlgProc(PWND, UINT, DWORD, LONG);
/*
* SEB_CREATEPARMS structure is passed to WM_DIALOGINIT of
* WOWSysErrorBoxDlgProc.
*
*/
typedef struct _SEB_CREATEPARMS {
LPWSTR szTitle;
LPWSTR szMessage;
LPWSTR rgszBtn[3];
BOOL rgfDefButton[3];
WORD wBtnCancel;
} SEB_CREATEPARMS, *PSEB_CREATEPARMS;
VOID
LogErrorPopup(
IN LPWSTR Caption,
IN LPWSTR Message
)
{
LPWSTR lps[2];
lps[0] = Caption;
lps[1] = Message;
if ( EventSource ) {
LeaveCrit();
ReportEvent(
EventSource,
EVENTLOG_INFORMATION_TYPE,
0,
STATUS_LOG_HARD_ERROR,
NULL,
2,
0,
&lps[0],
NULL
);
EnterCrit();
}
}
static WCHAR wszDosDevices[] = L"\\??\\A:";
VOID
SubstituteDeviceName(
PUNICODE_STRING InputDeviceName,
LPSTR OutputDriveLetter
)
{
UNICODE_STRING LinkName;
UNICODE_STRING DeviceName;
OBJECT_ATTRIBUTES Obja;
HANDLE LinkHandle;
NTSTATUS Status;
ULONG i;
PWCHAR p;
WCHAR DeviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
RtlInitUnicodeString(&LinkName,wszDosDevices);
p = (PWCHAR)LinkName.Buffer;
p = p+12;
for(i=0;i<26;i++){
*p = (WCHAR)'A' + (WCHAR)i;
InitializeObjectAttributes(
&Obja,
&LinkName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenSymbolicLinkObject(
&LinkHandle,
SYMBOLIC_LINK_QUERY,
&Obja
);
if (NT_SUCCESS( Status )) {
//
// Open succeeded, Now get the link value
//
DeviceName.Length = 0;
DeviceName.MaximumLength = sizeof(DeviceNameBuffer);
DeviceName.Buffer = DeviceNameBuffer;
Status = NtQuerySymbolicLinkObject(
LinkHandle,
&DeviceName,
NULL
);
NtClose(LinkHandle);
if ( NT_SUCCESS(Status) ) {
if ( RtlEqualUnicodeString(InputDeviceName,&DeviceName,TRUE) ) {
OutputDriveLetter[0]='A'+(WCHAR)i;
OutputDriveLetter[1]=':';
OutputDriveLetter[2]='\0';
return;
}
}
}
}
}
DWORD GetErrorMode(VOID)
{
HANDLE hKey;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES OA;
LONG Status;
BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
DWORD cbSize;
DWORD dwRet = 0;
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows");
InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtOpenKey(&hKey, KEY_READ, &OA);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString(&UnicodeString, L"ErrorMode");
Status = NtQueryValueKey(hKey,
&UnicodeString,
KeyValuePartialInformation,
(PKEY_VALUE_PARTIAL_INFORMATION)Buf,
sizeof(Buf),
&cbSize);
if (NT_SUCCESS(Status)) {
dwRet = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data);
}
NtClose(hKey);
}
return dwRet;
}
BOOL CALLBACK WindowEnumProc(
HWND hwnd,
LPARAM lParam)
{
#ifdef FE_IME // WindowEnumProc()
/*
* LATER: We need check IME-UI/IME class.
* if we get IME-UI/IME class, we should skip it.
*/
*(HWND *)lParam = hwnd;
#else
*(HWND *)lParam = hwnd;
#endif // FE_IME
return FALSE;
}
/***************************************************************************\
* HardErrorHandler
*
* This routine processes hard error requests from the CSR exception port
*
* History:
* 07-03-91 JimA Created.
\***************************************************************************/
VOID HardErrorHandler()
{
NTSTATUS Status;
int idResponse;
LPSTR lpCaption, alpCaption;
LPWSTR lpMessage, lpFullCaption;
PHARDERROR_MSG phemsg;
DWORD cbCaption;
HANDLE ClientProcess;
DWORD ParameterVector[MAXIMUM_HARDERROR_PARAMETERS];
DWORD Counter;
DWORD StringsToFreeMask;
UNICODE_STRING ScratchU;
UNICODE_STRING LocalU;
ANSI_STRING LocalA;
LPSTR formatstring;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
LPWSTR ApplicationNameString;
BOOL ApplicationNameAllocated;
LPWSTR ApplicationName;
BOOL ApplicationNameIsStatic;
LONG ApplicationNameLength;
BOOL fFreeCaption;
PHARDERRORINFO phi, *pphi;
PCSR_THREAD DerefThread;
DWORD dwMBFlags;
WCHAR *pResBuffer;
BOOL ResAllocated;
DWORD dwResponse;
BOOLEAN ErrorIsFromSystem;
if (!NtUserHardErrorControl(HardErrorSetup, NULL)) {
/*
* We failed to set up to process hard errors. Acknowledge all
* pending errors as NotHandled.
*/
pphi = &gphiList;
while (gphiList != NULL) {
phi = gphiList;
gphiList = phi->phiNext;
/*
* Set the response as not handled
*/
phi->pmsg->Response = ResponseNotHandled;
/*
* Signal HardError() that we're done.
*/
if (phi->hEventHardError == NULL) {
Status = NtReplyPort(((PCSR_THREAD)phi->pthread)->Process->ClientPort,
(PPORT_MESSAGE)phi->pmsg);
LeaveCrit();
CsrDereferenceThread(phi->pthread);
EnterCrit();
LocalFree(phi->pmsg);
} else {
NtSetEvent(phi->hEventHardError, NULL);
}
LocalFree(phi);
}
return;
}
gdwHardErrorThreadId = (DWORD)NtCurrentTeb()->ClientId.UniqueThread;
if (NtDllHandle == NULL) {
LeaveCrit();
NtDllHandle = GetModuleHandle(TEXT("ntdll"));
EnterCrit();
}
UserAssert(NtDllHandle != NULL);
DerefThread = NULL;
if ( !EventSource ) {
LeaveCrit();
EventSource = RegisterEventSourceW(NULL,L"Application Popup");
EnterCrit();
if ( EventSource ) {
HardErrorReportMode = GetErrorMode();
} else {
HardErrorReportMode = 0;
}
} else {
HardErrorReportMode = GetErrorMode();
}
for (;;) {
/*
* If no messages are pending, we're done.
*/
if ( DerefThread ) {
LeaveCrit();
CsrDereferenceThread(DerefThread);
DerefThread = NULL;
EnterCrit();
}
if (gphiList == NULL) {
NtUserHardErrorControl(HardErrorCleanup, NULL);
gdwHardErrorThreadId = 0;
return;
}
/*
* Process the error from the tail of the list.
*/
for (phi = gphiList; phi->phiNext != NULL; phi = phi->phiNext)
;
phemsg = phi->pmsg;
phemsg->Response = ResponseNotHandled;
//
// Compute the hard error parameter and store them in
// the parameter vector
//
StringsToFreeMask = 0;
ClientProcess = NULL;
ClientProcess = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
(DWORD)phemsg->h.ClientId.UniqueProcess
);
for(Counter = 0;Counter < phemsg->NumberOfParameters;Counter++) {
ParameterVector[Counter] = phemsg->Parameters[Counter];
}
while(Counter < MAXIMUM_HARDERROR_PARAMETERS)
ParameterVector[Counter++] = (DWORD)L"";
//
// If there are unicode strings, then we need to get them
// convert them to ansi and then store them in the
// parameter vector
//
if ( phemsg->UnicodeStringParameterMask ) {
for(Counter = 0;Counter < phemsg->NumberOfParameters;Counter++) {
//
// if there is a string in this position,
// then grab it
if ( phemsg->UnicodeStringParameterMask & 1 << Counter ) {
//
// Point to an empty string in case we don't have
// a client to read from or something fails later on.
//
ParameterVector[Counter] = (DWORD)"";
if ( ClientProcess ) {
Status = NtReadVirtualMemory(
ClientProcess,
(PVOID)phemsg->Parameters[Counter],
(PVOID)&ScratchU,
sizeof(ScratchU),
NULL
);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("Failed to read error string struct!\n"));
continue;
}
LocalU = ScratchU;
LocalU.Buffer = (PWSTR)LocalAlloc(
LMEM_ZEROINIT,
LocalU.MaximumLength
);
if ( !LocalU.Buffer ) {
KdPrint(("Failed to alloc string buffer!\n"));
continue;
}
Status = NtReadVirtualMemory(
ClientProcess,
(PVOID)ScratchU.Buffer,
(PVOID)LocalU.Buffer,
LocalU.MaximumLength,
NULL
);
if ( !NT_SUCCESS(Status) ) {
LocalFree(LocalU.Buffer);
KdPrint(("Failed to read error string!\n"));
continue;
}
RtlUnicodeStringToAnsiString(&LocalA, &LocalU, TRUE);
//
// check to see if string contains an NT
// device name. If so, then attempt a
// drive letter substitution
//
if ( strstr(LocalA.Buffer,"\\Device") == LocalA.Buffer ) {
SubstituteDeviceName(&LocalU,LocalA.Buffer);
}
else
if ( LocalA.Length > 4 && !_strnicmp(LocalA.Buffer, "\\??\\", 4) ) {
strcpy( LocalA.Buffer, LocalA.Buffer+4 );
LocalA.Length -= 4;
}
LocalFree(LocalU.Buffer);
StringsToFreeMask |= (1 << Counter);
ParameterVector[Counter] = (DWORD)LocalA.Buffer;
}
}
}
}
//
// Special-case STATUS_VDM_HARD_ERROR, which is raised by the VDM process
// when a 16-bit fault must be handled without any reentrancy.
//
if (phemsg->Status == STATUS_VDM_HARD_ERROR) {
dwResponse = DisplayVDMHardError(ParameterVector);
goto Reply;
}
ApplicationNameString = ServerLoadString(
hModuleWin,
STR_UNKNOWN_APPLICATION,
L"System Process",
&ApplicationNameAllocated
);
ApplicationName = ApplicationNameString;
ApplicationNameIsStatic = TRUE;
dwMBFlags = wIcons[(ULONG)(phemsg->Status) >> 30] |
wOptions[phemsg->ValidResponseOptions];
if ( ClientProcess ) {
PPEB Peb;
PROCESS_BASIC_INFORMATION BasicInfo;
PLDR_DATA_TABLE_ENTRY LdrEntry;
LDR_DATA_TABLE_ENTRY LdrEntryData;
PLIST_ENTRY LdrHead, LdrNext;
PPEB_LDR_DATA Ldr;
PVOID ImageBaseAddress;
PWSTR ClientApplicationName;
#ifndef UNICODE
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
#endif
ErrorIsFromSystem = FALSE;
//
// Pick up the application name.
//
//
// This is cumbersome, but basically, we locate the processes
// loader data table and get it's name directly out of the
// loader table
//
Status = NtQueryInformationProcess(
ClientProcess,
ProcessBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
NULL
);
if (!NT_SUCCESS(Status)) {
ErrorIsFromSystem = TRUE;
goto noname;
}
Peb = BasicInfo.PebBaseAddress;
if ( !Peb ) {
ErrorIsFromSystem = TRUE;
goto noname;
}
//
// Ldr = Peb->Ldr
//
Status = NtReadVirtualMemory(
ClientProcess,
&Peb->Ldr,
&Ldr,
sizeof(Ldr),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto noname;
}
LdrHead = &Ldr->InLoadOrderModuleList;
//
// LdrNext = Head->Flink;
//
Status = NtReadVirtualMemory(
ClientProcess,
&LdrHead->Flink,
&LdrNext,
sizeof(LdrNext),
NULL
);
if ( !NT_SUCCESS(Status) ) {
goto noname;
}
if ( LdrNext != LdrHead ) {
//
// This is the entry data for the image.
//
LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
Status = NtReadVirtualMemory(
ClientProcess,
LdrEntry,
&LdrEntryData,
sizeof(LdrEntryData),
NULL
);
if ( !NT_SUCCESS(Status)) {
goto noname;
}
Status = NtReadVirtualMemory(
ClientProcess,
&Peb->ImageBaseAddress,
&ImageBaseAddress,
sizeof(ImageBaseAddress),
NULL
);
if ( !NT_SUCCESS(Status)) {
goto noname;
}
if (ImageBaseAddress != LdrEntryData.DllBase) {
goto noname;
}
LdrNext = LdrEntryData.InLoadOrderLinks.Flink;
ClientApplicationName = (PWSTR)LocalAlloc(LMEM_ZEROINIT, LdrEntryData.BaseDllName.MaximumLength);
if ( !ClientApplicationName ) {
goto noname;
}
Status = NtReadVirtualMemory(
ClientProcess,
LdrEntryData.BaseDllName.Buffer,
ClientApplicationName,
LdrEntryData.BaseDllName.MaximumLength,
NULL
);
if ( !NT_SUCCESS(Status)) {
LocalFree(ClientApplicationName);
goto noname;
}
#ifndef UNICODE
//
// Now we have a unicode Application Name. Convert to ANSI
//
RtlInitUnicodeString(&UnicodeString, ClientApplicationName);
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
if ( !NT_SUCCESS(Status) ) {
LocalFree(ClientApplicationName);
goto noname;
}
ApplicationName = AnsiString.Buffer;
#else
ApplicationName = ClientApplicationName;
#endif
ApplicationNameIsStatic = FALSE;
}
noname:
NtClose(ClientProcess);
ClientProcess = NULL;
} else {
ErrorIsFromSystem = TRUE;
}
Status = RtlFindMessage( (PVOID)NtDllHandle,
(ULONG)RT_MESSAGETABLE,
LANG_NEUTRAL,
phemsg->Status,
&MessageEntry
);
alpCaption = lpCaption = NULL;
fFreeCaption = FALSE;
if (!NT_SUCCESS( Status )) {
formatstring = "Unknown Hard Error";
} else {
lpCaption = MessageEntry->Text;
formatstring = lpCaption;
/*
* If the message starts with a '{', it has a caption.
*/
if (*lpCaption == '{') {
cbCaption = 0;
lpCaption++;
formatstring++;
#ifdef FE_SB // HardErrorHandler()
while (*formatstring) {
if (IsDBCSLeadByte(*formatstring)) {
formatstring++;
cbCaption += 1;
if(*formatstring) {
formatstring++;
cbCaption += 1;
}
} else if(*formatstring != '}' ) {
formatstring++;
cbCaption += 1;
} else {
break;
}
}
#else
while ( *formatstring && *formatstring != '}' ) {
formatstring++;
cbCaption += 1;
}
#endif // FE_SB
if (*formatstring)
formatstring++;
/*
* Eat any non-printable stuff, up to the NULL
*/
while ( *formatstring && (unsigned char)*formatstring <= ' ') {
*formatstring++;
}
if (cbCaption++ > 0 && (alpCaption =
(LPSTR)LocalAlloc(LPTR, cbCaption)) != NULL) {
RtlMoveMemory(alpCaption, lpCaption, cbCaption - 1);
fFreeCaption = TRUE;
}
}
if (*formatstring == 0) {
formatstring = "Unknown Hard Error";
}
}
if (alpCaption == NULL) {
switch (phemsg->Status & ERROR_SEVERITY_ERROR) {
case ERROR_SEVERITY_SUCCESS:
alpCaption = pszaSUCCESS;
break;
case ERROR_SEVERITY_INFORMATIONAL:
alpCaption = pszaSYSTEM_INFORMATION;
break;
case ERROR_SEVERITY_WARNING:
alpCaption = pszaSYSTEM_WARNING;
break;
case ERROR_SEVERITY_ERROR:
alpCaption = pszaSYSTEM_ERROR;
break;
}
}
cbCaption = strlen(alpCaption) + 1;
//
// Special case UAE
//
if ( phemsg->Status == STATUS_UNHANDLED_EXCEPTION ) {
Status = RtlFindMessage( (PVOID)NtDllHandle,
(ULONG)RT_MESSAGETABLE,
LANG_NEUTRAL,
ParameterVector[0],
&MessageEntry
);
if (!NT_SUCCESS( Status )) {
UNICODE_STRING us1;
ANSI_STRING as1;
NTSTATUS trstatus;
/*
* The format specifier %s appears in some message strings.
* This was meant to be ANSI so we need to call wsprintfA
* first so %s is interpreted correctly.
*/
pResBuffer = ServerLoadString(
hModuleWin,
STR_UNKNOWN_EXCEPTION,
L"Unknown software exception",
&ResAllocated
);
RtlInitUnicodeString(&us1,pResBuffer);
trstatus = RtlUnicodeStringToAnsiString(&as1,&us1,TRUE);
if ( NT_SUCCESS(trstatus) ) {
wsprintfA(HEAnsiBuf, formatstring, as1.Buffer,
ParameterVector[0],
ParameterVector[1]
);
RtlFreeAnsiString(&as1);
} else {
wsprintfA(HEAnsiBuf, formatstring, "unknown software exception",
ParameterVector[0],
ParameterVector[1]
);
}
if ( ResAllocated ) {
LocalFree(pResBuffer);
}
wsprintfW(HardErrorachStatus, L"%hs", HEAnsiBuf);
} else {
//
// Access Violations are handled a bit differently
//
if ( ParameterVector[0] == STATUS_ACCESS_VIOLATION ) {
wsprintfA(HEAnsiBuf, MessageEntry->Text, ParameterVector[1],
ParameterVector[3],
ParameterVector[2] ? "written" : "read"
);
wsprintfW(HardErrorachStatus, L"%hs", HEAnsiBuf);
} else if ( ParameterVector[0] == STATUS_IN_PAGE_ERROR ) {
wsprintfA(HEAnsiBuf, MessageEntry->Text, ParameterVector[1],
ParameterVector[3],
ParameterVector[2]
);
wsprintfW(HardErrorachStatus, L"%hs", HEAnsiBuf);
} else {
lpCaption = MessageEntry->Text;
if ( !strncmp(lpCaption, "{EXCEPTION}", strlen("{EXCEPTION}")) ) {
while ( *lpCaption >= ' ' ) {
lpCaption++;
}
while ( *lpCaption && *lpCaption <= ' ') {
*lpCaption++;
}
//
// This is a marked exception. The lpCaption pointer
// points at the exception-name.
//
} else {
lpCaption = "unknown software exception";
}
wsprintfA(HEAnsiBuf, formatstring, lpCaption,
ParameterVector[0],
ParameterVector[1]
);
wsprintfW(HardErrorachStatus, L"%hs", HEAnsiBuf);
}
pResBuffer = ServerLoadString(
hModuleWin,
STR_OK_TO_TERMINATE,
L"Click on OK to terminate the application",
&ResAllocated
);
wcscat(
HardErrorachStatus,
TEXT("\n")
);
wcscat(
HardErrorachStatus,
pResBuffer
);
if ( ResAllocated ) {
LocalFree(pResBuffer);
}
#if DEVL
if ( phemsg->ValidResponseOptions == OptionOkCancel ) {
pResBuffer = ServerLoadString(
hModuleWin,
STR_CANCEL_TO_DEBUG,
L"Click on CANCEL xx to debug the application",
&ResAllocated
);
wcscat(
HardErrorachStatus,
TEXT("\n")
);
wcscat(
HardErrorachStatus,
pResBuffer
);
if ( ResAllocated ) {
LocalFree(pResBuffer);
}
}
#endif // DEVL
}
} else if (phemsg->Status == STATUS_SERVICE_NOTIFICATION) {
wsprintfW(HardErrorachStatus, L"%hs", ParameterVector[0]);
lpFullCaption = LocalAlloc(LPTR,
(strlen((LPSTR)ParameterVector[1]) + 1) * sizeof(WCHAR));
wsprintfW(lpFullCaption, L"%hs", ParameterVector[1]);
dwMBFlags = ParameterVector[2] & ~MB_SERVICE_NOTIFICATION;
} else {
try {
wsprintfA(HEAnsiBuf, formatstring, ParameterVector[0],
ParameterVector[1],
ParameterVector[2],
ParameterVector[3]);
#ifdef FE_SB // HardErrorHandler()
{
//
// Won't replace 0xd 0xa with space.
// Eliminate it, if the character is between DBCS characters.
//
// [Rules]
// + {DBC}0xd0xa{DBC} -> {DBC}{DBC}
// + {DBC}0xd0xa{SBC} -> {DBC} {SBC}
// + {SBC}0xd0xa{DBC} -> {SBC} {DBC}
// + {SBC}0xd0xa{SBC} -> {SBC} {SBC}
//
BOOL bLastCharIsDbcs = FALSE;
UINT cSkip = 0;
LPSTR startSkip = NULL;
formatstring = HEAnsiBuf;
while (*formatstring) {
switch (*formatstring) {
case 0xa:
case 0xd:
if (cSkip == 0) {
startSkip = formatstring;
}
cSkip++;
break;
default:
if (cSkip) {
UserAssert(startSkip != NULL);
if(bLastCharIsDbcs && IsDBCSLeadByte(*formatstring)) {
//
// Overwrite skipped character.
//
strcpy(startSkip,formatstring);
//
// Adjust current pointer.
//
formatstring = startSkip;
} else {
//
// Fill skipped character with ' '.
//
*startSkip = ' ';
//
// Overwrite skiped charcter..
//
strcpy(startSkip+1,formatstring);
//
// Adjust pointer...
//
formatstring = startSkip+1;
}
cSkip = 0;
startSkip = NULL;
}
if (IsDBCSLeadByte(*formatstring)) {
//
// This is DBCS character.
//
formatstring++;
if (*formatstring) {
//
// Mark as DBCS character.
//
bLastCharIsDbcs = TRUE;
} else {
//
// Reach end-of-string.
// DBCS char will be displayed as garbage....
//
goto EndOfString;
}
} else {
bLastCharIsDbcs = FALSE;
}
break;
}
formatstring++;
}
//
// This is for following case...
//
// +) 0xa0xd0x0.
//
// We will trim unnessesary 0xa 0xd character.
//
if (cSkip) {
UserAssert(startSkip != NULL);
startSkip = '\0';
}
EndOfString: ;
}
#else
formatstring = HEAnsiBuf;
while ( *formatstring ) {
if ( *formatstring == 0xd ) {
*formatstring = ' ';
//
// Move everything up if a CR LF sequence is found
//
if ( *(formatstring+1) == 0xa ) {
strcpy(formatstring, formatstring+1);
}
}
if ( *formatstring == 0xa ) {
*formatstring = ' ';
}
formatstring++;
}
#endif // FE_SB
wsprintfW(HardErrorachStatus, L"%hs", HEAnsiBuf);
}
except(EXCEPTION_EXECUTE_HANDLER) {
wsprintfW(HardErrorachStatus, L"Exception Processing Message %lx Parameters %lx %lx %lx %lx", phemsg->Status,
ParameterVector[0],
ParameterVector[1],
ParameterVector[2],
ParameterVector[3]);
}
}
lpMessage = HardErrorachStatus;
for(Counter = 0;Counter < phemsg->NumberOfParameters;Counter++) {
//
// if there is a string in this position,
// then free it
if ( StringsToFreeMask & (1 << Counter) ) {
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)ParameterVector[Counter]);
}
}
if (phemsg->Status != STATUS_SERVICE_NOTIFICATION) {
HWND hwndOwner = NULL;
DWORD cbTitle;
LPWSTR lpTitle;
ApplicationNameLength = (wcslen(ApplicationName) +
wcslen(TEXT(" - ")) + 2)*sizeof(WCHAR);
/*
* if UNICODE :
* need count of bytes when ANSI Caption is output as Unicode
* LATER IanJa: eventually the caption will be Unicode too, so
* cbCaption will already be correct and won't need doubling.
*/
cbCaption *= sizeof(WCHAR);
/*
* If the client is a Windows thread, find a top-level window
* belonging to the thread to act as the owner
*/
EnumThreadWindows((DWORD)phemsg->h.ClientId.UniqueThread,
WindowEnumProc, (LPARAM)&hwndOwner);
/*
* Add a window title, if possible
*/
if (hwndOwner != NULL) {
/*
* Get the window title, if it has one.
*/
cbTitle = GetWindowTextLengthW(hwndOwner);
if (cbTitle != 0) {
/*
* Alloc a buffer and query the text
*/
lpTitle = LocalAlloc(LPTR, (cbTitle + 1) * sizeof(WCHAR));
if (lpTitle != NULL)
GetWindowText(hwndOwner, lpTitle, cbTitle + 1);
else
cbTitle = 0; // allocation failed
}
}
if (hwndOwner != NULL && cbTitle != 0) {
cbCaption += (cbTitle * sizeof(WCHAR)) + sizeof(TEXT(": "));
lpFullCaption = (LPWSTR)LocalAlloc(LPTR, cbCaption+ApplicationNameLength);
if (lpFullCaption != NULL)
wsprintfW(
lpFullCaption,
L"%ls: %ls - %hs",
lpTitle,
ApplicationName,
alpCaption
);
LocalFree(lpTitle);
} else {
lpFullCaption = (LPWSTR)LocalAlloc(LPTR, cbCaption+ApplicationNameLength);
if (lpFullCaption != NULL)
wsprintfW(
lpFullCaption,
L"%ls - %hs",
ApplicationName,
alpCaption
);
}
}
if (fFreeCaption)
LocalFree(alpCaption);
//
// Add the application name to the caption
//
if ( phemsg->Status == STATUS_SERVICE_NOTIFICATION ||
HardErrorReportMode == 0 ||
HardErrorReportMode == 1 && ErrorIsFromSystem == FALSE ) {
do
{
gfHardError = HEF_NORMAL;
phemsg->Response = ResponseNotHandled;
if (NtUserHardErrorControl((dwMBFlags & MB_DEFAULT_DESKTOP_ONLY) ?
HardErrorAttachUser : HardErrorAttach, NULL)) {
/*
* We have already handled the MB_DEFAULT_DESKTOP_ONLY and
* MB_SERVICE_NOTIFICATION flags. Clear them to prevent
* recursion.
*/
dwMBFlags &= ~(MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION);
/*
* Bring up the message box. OR in MB_SETFOREGROUND so the
* it comes up on top.
*
* NOTE; This only works with a single visible windowstation.
*/
LeaveCrit();
idResponse = MessageBoxEx(NULL, lpMessage, lpFullCaption,
dwMBFlags | MB_SYSTEMMODAL | MB_SETFOREGROUND, 0);
EnterCrit();
if (NtUserHardErrorControl(HardErrorDetach, NULL))
gfHardError = HEF_SWITCH;
} else {
idResponse = 0;
}
dwResponse = dwResponses[idResponse];
} while (gfHardError == HEF_SWITCH);
if ( ErrorIsFromSystem ) {
LogErrorPopup(lpFullCaption,lpMessage);
}
} else {
//
// We have selected mode 1 and the error is from within the system.
// log the message and continue
// Or, We selected mode 2 which says to log all hard errors
//
LogErrorPopup(lpFullCaption,lpMessage);
dwResponse = dwResponseDefault[phemsg->ValidResponseOptions];
}
/*
* Free all allocated stuff
*/
if (lpFullCaption != NULL)
LocalFree(lpFullCaption);
if ( ApplicationNameIsStatic == FALSE ) {
LocalFree(ApplicationName);
}
if ( ApplicationNameAllocated ) {
LocalFree(ApplicationNameString);
}
if (gfHardError != HEF_RESTART) {
Reply:
/*
* Unlink the error from the list.
*/
for (
pphi = &gphiList;
(*pphi != NULL) && (*pphi != phi);
pphi = &(*pphi)->phiNext)
;
if (*pphi != NULL) {
*pphi = phi->phiNext;
/*
* Save the response
*/
phemsg->Response = dwResponse;
/*
* Signal HardError() that we're done.
*/
if (phi->hEventHardError == NULL) {
Status = NtReplyPort(((PCSR_THREAD)phi->pthread)->Process->ClientPort,
(PPORT_MESSAGE)phi->pmsg);
DerefThread = (PCSR_THREAD)phi->pthread;
LocalFree(phi->pmsg);
} else {
NtSetEvent(phi->hEventHardError, NULL);
}
LocalFree(phi);
}
} else {
/*
* Don't dereference yet.
*/
DerefThread = NULL;
}
}
}
LPWSTR RtlLoadStringOrError(
HANDLE hModule,
UINT wID,
LPWSTR lpDefault,
PBOOL pAllocated,
BOOL bAnsi
)
{
LPTSTR lpsz;
int cch;
LPWSTR lpw;
PMESSAGE_RESOURCE_ENTRY MessageEntry;
NTSTATUS Status;
cch = 0;
lpw = NULL;
Status = RtlFindMessage((PVOID)hModule, (ULONG)RT_MESSAGETABLE,
0, wID, &MessageEntry);
if (NT_SUCCESS(Status)) {
/*
* Return two fewer chars so the crlf in the message will be
* stripped out.
*/
cch = wcslen((PWCHAR)MessageEntry->Text) - 2;
lpsz = (LPWSTR)MessageEntry->Text;
if (bAnsi) {
int ich;
/*
* Add one to zero terminate then force the termination
*/
ich = WCSToMB(lpsz, cch+1, (CHAR **)&lpw, -1, TRUE);
((LPSTR)lpw)[ich-1] = 0;
}
else {
lpw = (LPWSTR)LocalAlloc(LMEM_ZEROINIT,(cch+1)*sizeof(WCHAR));
if ( lpw ) {
/*
* Copy the string into the buffer.
*/
RtlCopyMemory(lpw, lpsz, cch*sizeof(WCHAR));
}
}
}
if ( !lpw ) {
lpw = lpDefault;
*pAllocated = FALSE;
} else {
*pAllocated = TRUE;
}
return lpw;
}
DWORD DisplayVDMHardError(
LPDWORD Parameters
)
{
SEB_CREATEPARMS sebcp;
WORD rgwBtn[3];
WORD wBtn;
int i;
DWORD dwResponse;
LPWSTR apstrButton[3];
int aidButton[3];
int defbutton;
int cButtons = 0;
BOOL fAlloc = TRUE;
MSGBOXDATA mbd;
//
// STATUS_VDM_HARD_ERROR was raised as a hard error.
//
// Right now, only WOW does this. If NTVDM does it,
// fForWOW will be false.
//
// The 4 parameters are as follows:
//
// Parameters[0] = (fForWOW << 16) | wBtn1;
// Parameters[1] = (wBtn2 << 16) | wBtn3;
// Parameters[2] = (DWORD) szTitle;
// Parameters[3] = (DWORD) szMessage;
//
rgwBtn[0] = LOWORD(Parameters[0]);
rgwBtn[1] = HIWORD(Parameters[1]);
rgwBtn[2] = LOWORD(Parameters[1]);
/*
* Get the error text and convert it to unicode. Note that the
* buffers are allocated from the process heap, so we can't
* use LocalFree when we free them.
*/
try {
MBToWCS((LPSTR)Parameters[2], -1, &sebcp.szTitle, -1, TRUE);
MBToWCS((LPSTR)Parameters[3], -1, &sebcp.szMessage, -1, TRUE);
} except (EXCEPTION_EXECUTE_HANDLER) {
sebcp.szTitle = TEXT("VDM Internal Error");
sebcp.szMessage = TEXT("Exception retrieving error text.");
fAlloc = FALSE;
}
/*
* Setup rgszBtn[x] and rgfDefButton[x] for each button.
* wBtnCancel is the button # to return when IDCANCEL
* is received (because the user hit Esc).
*/
sebcp.wBtnCancel = 0;
defbutton = 0;
for (i = 0; i < 3; i++) {
wBtn = rgwBtn[i] & ~SEB_DEFBUTTON;
if (wBtn && wBtn <= MAX_SEB_STYLES) {
apstrButton[cButtons] = MB_GetString(wBtn-1);
aidButton[cButtons] = i + 1;
if (rgwBtn[i] & SEB_DEFBUTTON) {
defbutton = cButtons;
}
if (wBtn == SEB_CANCEL) {
sebcp.wBtnCancel = cButtons;
}
cButtons++;
}
}
/*
* Pop the dialog. Code copied from HardErrorThread above.
*/
if ( HardErrorReportMode == 0 || HardErrorReportMode == 1 ) {
do {
gfHardError = HEF_NORMAL;
dwResponse = 0;
if (NtUserHardErrorControl(HardErrorAttach, NULL)) {
/*
* Bring up the dialog box.
*/
memset(&mbd, 0, sizeof(MSGBOXDATA));
mbd.cbSize = sizeof(MSGBOXPARAMS);
mbd.lpszText = sebcp.szMessage;
mbd.lpszCaption = sebcp.szTitle;
mbd.dwStyle = MB_SYSTEMMODAL | MB_SETFOREGROUND;
if ((cButtons != 1) || (aidButton[0] != 1))
mbd.dwStyle |= MB_OKCANCEL;
mbd.pidButton = aidButton;
mbd.ppszButtonText = apstrButton;
mbd.cButtons = cButtons;
mbd.DefButton = defbutton;
mbd.CancelId = sebcp.wBtnCancel;
LeaveCrit();
dwResponse = SoftModalMessageBox( &mbd );
EnterCrit();
if (NtUserHardErrorControl(HardErrorDetach, NULL))
gfHardError = HEF_SWITCH;
}
} while (gfHardError == HEF_SWITCH);
} else {
//
// We have selected mode 1 and the error is from within the system.
// log the message and continue
// Or, We selected mode 2 which says to log all hard errors
//
LogErrorPopup(sebcp.szTitle,sebcp.szMessage);
dwResponse = ResponseOk;
}
if (fAlloc) {
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)sebcp.szTitle);
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)sebcp.szMessage);
}
return dwResponse;
}
/***************************************************************************\
* UserHardError
*
* Called from CSR to pop up hard error messages
*
* History:
* 07-03-91 JimA Created.
\***************************************************************************/
VOID UserHardError(
PCSR_THREAD pt,
PHARDERROR_MSG pmsg)
{
PHARDERRORINFO phi;
HANDLE hEvent;
/*
* Set up error return in case of failure.
*/
pmsg->Response = ResponseNotHandled;
/*
* Return if the process has terminated.
*/
if (pt != NULL && pt->Process->Flags & CSR_PROCESS_TERMINATED)
return;
EnterCrit(); // to synchronize heap calls
phi = (PHARDERRORINFO)LocalAlloc(LPTR, sizeof(HARDERRORINFO));
if (phi == NULL) {
LeaveCrit();
return;
}
/*
* Set up how the handler will acknowledge the error.
*/
phi->pthread = pt;
if ( pt && pt->Process->ClientPort ) {
phi->pmsg = (PHARDERROR_MSG)LocalAlloc(LPTR,
pmsg->h.u1.s1.TotalLength);
if (phi->pmsg == NULL) {
LocalFree(phi);
LeaveCrit();
return;
}
/*
* Do a wait reply for csr clients
*/
RtlCopyMemory(phi->pmsg, pmsg, pmsg->h.u1.s1.TotalLength);
pmsg->Response = (ULONG)-1;
hEvent = NULL;
} else {
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL) {
LocalFree(phi);
LeaveCrit();
return;
}
/*
* Wait for the user to acknowledge the error if it's coming from a
* non-csr source
*/
phi->pmsg = pmsg;
phi->hEventHardError = hEvent;
}
/*
* Queue the error message.
*/
phi->phiNext = gphiList;
gphiList = phi;
/*
* If no other thread is currently handling the errors, this
* thread will do it.
*/
if (gdwHardErrorThreadId == 0) {
HardErrorHandler();
}
/*
* If there is an event handle, wait for it.
*/
LeaveCrit();
if (hEvent != NULL) {
NtWaitForSingleObject(hEvent, FALSE, NULL);
NtClose(hEvent);
}
}
/***************************************************************************\
* BoostHardError
*
* If one or more hard errors exist for the specified process, remove
* them from the list if forced, otherwise bring the first one to the
* top of the hard error list and display it. Return TRUE if there
* is a hard error.
*
* History:
* 11-02-91 JimA Created.
\***************************************************************************/
BOOL BoostHardError(
DWORD dwProcessId,
BOOL fForce)
{
HDESK hdeskSave;
PHARDERRORINFO phi, *pphi;
BOOL fHasError = FALSE;
BOOL fWasActive = FALSE;
BOOL fWasInCrit;
HANDLE hThreadId;
int cTries = 0;
if (gphiList == NULL)
return FALSE;
/*
* Save the state of the critical section. If we are in it,
* we must leave it prior to calling GetThreadDesktop.
*/
hThreadId = NtCurrentTeb()->ClientId.UniqueThread;
fWasInCrit = (gcsUserSrv.OwningThread == hThreadId);
if (fWasInCrit)
LeaveCrit();
/*
* Save current desktop in case we need to change desktops
* to activate windows.
*/
hdeskSave = GetThreadDesktop(GetCurrentThreadId());
EnterCrit();
for (pphi = &gphiList; *pphi != NULL; ) {
if ((*pphi)->pthread != NULL &&
(*pphi)->pthread->ClientId.UniqueProcess == (HANDLE)dwProcessId) {
/*
* Found a hard error message.
*/
fHasError = TRUE;
if (fForce) {
/*
* Unlink it from the list.
*/
phi = *pphi;
*pphi = phi->phiNext;
fWasActive = (phi->phiNext == NULL);
/*
* Acknowledge the error as not handled.
*/
phi->pmsg->Response = ResponseNotHandled;
if (phi->hEventHardError == NULL) {
NtReplyPort(phi->pthread->Process->ClientPort,
(PPORT_MESSAGE)phi->pmsg);
LeaveCrit();
CsrDereferenceThread(phi->pthread);
EnterCrit();
LocalFree(phi->pmsg);
/*
* The list might have changed while we were outside the
* critical section, so start over.
*/
pphi = &gphiList;
cTries++;
} else {
NtSetEvent(phi->hEventHardError, NULL);
}
LocalFree(phi);
/*
* Bail out if we've already started over a bunch of times.
*/
if (cTries > 16) {
KdPrint(("BoostHardError exceeded max loop count\n"));
return TRUE;
}
} else {
/*
* If this is the last one in the list, we don't
* need to do anything to bring it up, just
* need to activate the popup.
*/
if ((*pphi)->phiNext == NULL) {
HWND hwndError = NULL;
/*
* Make the hard error foreground.
*/
EnumThreadWindows((DWORD)hThreadId,
WindowEnumProc, (LPARAM)&hwndError);
if (hwndError != NULL &&
NtUserHardErrorControl(HardErrorAttachNoQueue, NULL)) {
SetForegroundWindow(hwndError);
/*
* Release the desktop that was used.
*/
NtUserHardErrorControl(HardErrorDetachNoQueue, hdeskSave);
}
if (!fWasInCrit)
LeaveCrit();
return TRUE;
}
/*
* Unlink it from the list.
*/
phi = *pphi;
*pphi = phi->phiNext;
/*
* Put it on the tail of the list so it will come up first.
*/
while (*pphi != NULL)
pphi = &(*pphi)->phiNext;
*pphi = phi;
phi->phiNext = NULL;
break;
}
} else {
/*
* Step to the next error in the list.
*/
pphi = &(*pphi)->phiNext;
}
}
/*
* If the diplayed error was cleared and there is still
* a handler thread, restart the popup.
*/
if (fWasActive && gdwHardErrorThreadId != 0) {
gfHardError = HEF_RESTART;
PostThreadMessage(gdwHardErrorThreadId, WM_QUIT, 0, 0);
}
if (!fWasInCrit)
LeaveCrit();
return fHasError;
}