Author: fireball
Date: Sat Dec 22 20:18:32 2007
New Revision: 31400
URL:
http://svn.reactos.org/svn/reactos?rev=31400&view=rev
Log:
Dmitry Philippov
- Implement hard error message handler. Now whenever a hard error occurs (like an
exception in the win32 application, or missing DLL import), a user will be presented with
a nice message box saying about the problem.
Modified:
trunk/reactos/subsystems/win32/csrss/api/wapi.c
trunk/reactos/subsystems/win32/csrss/include/csrplugin.h
trunk/reactos/subsystems/win32/csrss/init.c
trunk/reactos/subsystems/win32/csrss/win32csr/dllmain.c
Modified: trunk/reactos/subsystems/win32/csrss/api/wapi.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/api…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/api/wapi.c (original)
+++ trunk/reactos/subsystems/win32/csrss/api/wapi.c Sat Dec 22 20:18:32 2007
@@ -106,7 +106,9 @@
}
}
-BOOL FASTCALL CallHardError(void);
+BOOL
+CallHardError(IN PCSRSS_PROCESS_DATA ProcessData,
+ IN PHARDERROR_MSG HardErrorMessage);
static
VOID
@@ -117,7 +119,7 @@
DPRINT1("CSR: received hard error %lx\n", Message->Status);
/* Call the hard error handler in win32csr */
- CallHardError();
+ (VOID)CallHardError(ProcessData, Message);
}
NTSTATUS STDCALL
Modified: trunk/reactos/subsystems/win32/csrss/include/csrplugin.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/inc…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/include/csrplugin.h (original)
+++ trunk/reactos/subsystems/win32/csrss/include/csrplugin.h Sat Dec 22 20:18:32 2007
@@ -43,7 +43,8 @@
typedef BOOL (STDCALL *CSRPLUGIN_INIT_COMPLETE_PROC)(void);
-typedef BOOL (STDCALL *CSRPLUGIN_HARDERROR_PROC)(void);
+typedef BOOL (STDCALL *CSRPLUGIN_HARDERROR_PROC)(IN PCSRSS_PROCESS_DATA ProcessData,
+ IN PHARDERROR_MSG HardErrorMessage);
typedef BOOL (STDCALL *CSRPLUGIN_INITIALIZE_PROC)(PCSRSS_API_DEFINITION *ApiDefinitions,
PCSRSS_OBJECT_DEFINITION
*ObjectDefinitions,
Modified: trunk/reactos/subsystems/win32/csrss/init.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/ini…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/init.c (original)
+++ trunk/reactos/subsystems/win32/csrss/init.c Sat Dec 22 20:18:32 2007
@@ -122,8 +122,8 @@
}
BOOL
-FASTCALL
-CallHardError(void)
+CallHardError(IN PCSRSS_PROCESS_DATA ProcessData,
+ IN PHARDERROR_MSG HardErrorMessage)
{
BOOL Ok;
unsigned i;
@@ -135,7 +135,7 @@
{
for (i = 0; i < HardErrorProcCount && Ok; i++)
{
- Ok = (*(HardErrorProcs[i]))();
+ Ok = (*(HardErrorProcs[i]))(ProcessData, HardErrorMessage);
}
}
Modified: trunk/reactos/subsystems/win32/csrss/win32csr/dllmain.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/win…
==============================================================================
--- trunk/reactos/subsystems/win32/csrss/win32csr/dllmain.c (original)
+++ trunk/reactos/subsystems/win32/csrss/win32csr/dllmain.c Sat Dec 22 20:18:32 2007
@@ -1,9 +1,9 @@
-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: subsys/csrss/win32csr/dllmain.c
* PURPOSE: Initialization
+ * PROGRAMMERS: Dmitry Philippov (shedon(a)mail.ru)
*/
/* INCLUDES ******************************************************************/
@@ -172,9 +172,376 @@
}
static BOOL STDCALL
-Win32CsrHardError(void)
-{
- MessageBox(0, "Hard Error", "TODO", 0);
+Win32CsrHardError(IN PCSRSS_PROCESS_DATA ProcessData,
+ IN PHARDERROR_MSG HardErrorMessage)
+{
+ UINT responce = MB_OK;
+ NTSTATUS Status;
+ HANDLE hProcess;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG nParam = 0;
+ PRTL_MESSAGE_RESOURCE_ENTRY MessageResource;
+ ULONG ParameterList[MAXIMUM_HARDERROR_PARAMETERS];
+ LPSTR CaptionText, MessageBody;
+ LPWSTR szxCaptionText, szxMessageBody;
+ DWORD SizeOfAllUnicodeStrings = 0;
+ PROCESS_BASIC_INFORMATION ClientBasicInfo;
+ UNICODE_STRING ClientFileNameU;
+ UNICODE_STRING TempStringU;
+ UNICODE_STRING ParameterStringU;
+ ANSI_STRING ParamStringA;
+ ULONG UnicodeStringParameterMask = HardErrorMessage->UnicodeStringParameterMask;
+ int MessageBoxResponse;
+
+ HardErrorMessage->Response = ResponseNotHandled;
+
+ DPRINT1("NumberOfParameters = %d\n",
HardErrorMessage->NumberOfParameters);
+ DPRINT1("Status = %lx\n", HardErrorMessage->Status);
+
+ // open client process
+ InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
+ Status = NtOpenProcess(&hProcess, PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
&ObjectAttributes, &HardErrorMessage->h.ClientId);
+ if( !NT_SUCCESS(Status) ) {
+ DPRINT1("NtOpenProcess failed with code: %lx\n", Status);
+ return FALSE;
+ }
+
+ // let's get a name of the client process to display it in the caption of a
message box
+
+ ClientFileNameU.MaximumLength = 0;
+ ClientFileNameU.Length = 0;
+ ClientFileNameU.Buffer = NULL;
+ Status = NtQueryInformationProcess(hProcess,
+ ProcessBasicInformation,
+ &ClientBasicInfo,
+ sizeof(ClientBasicInfo),
+ NULL);
+ if( NT_SUCCESS(Status) ) {
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Entry;
+ PLDR_DATA_TABLE_ENTRY Module;
+ PPEB_LDR_DATA Ldr;
+ PPEB Peb = ClientBasicInfo.PebBaseAddress;
+
+ if( Peb )
+ {
+ Status = NtReadVirtualMemory(hProcess, &Peb->Ldr, &Ldr,
sizeof(Ldr), NULL);
+ if( NT_SUCCESS(Status) ) {
+ ModuleListHead = &Ldr->InLoadOrderModuleList;
+ Status = NtReadVirtualMemory(
+ hProcess,
+ &ModuleListHead->Flink,
+ &Entry,
+ sizeof(Entry),
+ NULL
+ );
+
+ if( NT_SUCCESS(Status) )
+ {
+ if (Entry != ModuleListHead)
+ {
+ LDR_DATA_TABLE_ENTRY ModuleData;
+ Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
+
+ Status = NtReadVirtualMemory(hProcess, Module, &ModuleData,
sizeof(ModuleData), NULL);
+ if( NT_SUCCESS(Status) ) {
+ PVOID ClientDllBase;
+
+ Status = NtReadVirtualMemory(
+ hProcess,
+ &Peb->ImageBaseAddress,
+ &ClientDllBase,
+ sizeof(ClientDllBase),
+ NULL
+ );
+ if( NT_SUCCESS(Status) && (ClientDllBase ==
ModuleData.DllBase) ) {
+
+ ClientFileNameU.MaximumLength =
ModuleData.BaseDllName.MaximumLength;
+ ClientFileNameU.Buffer =
RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength);
+ Status = NtReadVirtualMemory(
+ hProcess,
+ ModuleData.BaseDllName.Buffer,
+ ClientFileNameU.Buffer,
+ ClientFileNameU.MaximumLength,
+ NULL
+ );
+ if( NT_SUCCESS(Status) ) {
+ ClientFileNameU.Length =
wcslen(ClientFileNameU.Buffer)*sizeof(wchar_t);
+ }
+ else {
+ RtlFreeHeap (RtlGetProcessHeap(), 0,
ClientFileNameU.Buffer);
+ ClientFileNameU.Buffer = NULL;
+ }
+
+ DPRINT("ClientFileNameU=\'%wZ\'\n",
&ClientFileNameU);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // read all unicode strings from client space
+ for(nParam = 0; nParam < HardErrorMessage->NumberOfParameters; nParam++,
UnicodeStringParameterMask >>= 1)
+ {
+ if( UnicodeStringParameterMask & 0x01 ) {
+ Status = NtReadVirtualMemory(hProcess,
+ (PVOID)HardErrorMessage->Parameters[nParam],
+ (PVOID)&TempStringU,
+ sizeof(TempStringU),
+ NULL);
+
+ if( NT_SUCCESS(Status) ) {
+ ParameterStringU.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, TempStringU.MaximumLength);
+ if( !ParameterStringU.Buffer ) {
+ DPRINT1("Cannot allocate memory %d\n",
TempStringU.MaximumLength);
+ NtClose(hProcess);
+ if( ClientFileNameU.Buffer ) {
+ RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer);
+ }
+ return FALSE;
+ }
+
+ Status = NtReadVirtualMemory(hProcess,
+ (PVOID)TempStringU.Buffer,
+ (PVOID)ParameterStringU.Buffer,
+ TempStringU.MaximumLength,
+ NULL);
+ if( !NT_SUCCESS(Status) ) {
+ DPRINT1("NtReadVirtualMemory failed with code: %lx\n",
Status);
+ RtlFreeHeap (RtlGetProcessHeap(), 0, ParameterStringU.Buffer);
+ if( ClientFileNameU.Buffer ) {
+ RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer);
+ }
+ NtClose(hProcess);
+ return FALSE;
+ }
+ ParameterStringU.Length = TempStringU.Length;
+ ParameterStringU.MaximumLength = TempStringU.MaximumLength;
+ DPRINT("ParameterStringU=\'%wZ\'\n",
&ParameterStringU);
+ RtlUnicodeStringToAnsiString(&ParamStringA, &ParameterStringU,
TRUE);
+ ParameterList[nParam] = (ULONG)ParamStringA.Buffer;
+ SizeOfAllUnicodeStrings += ParamStringA.MaximumLength;
+ }
+ }
+ else {
+ // it's not a unicode string
+ ParameterList[nParam] = HardErrorMessage->Parameters[nParam];
+ }
+ }
+
+ NtClose(hProcess);
+
+ // get text string of the error code
+ Status = RtlFindMessage(
+ (PVOID)GetModuleHandle(TEXT("ntdll")),
+ (ULONG)RT_MESSAGETABLE,
+ LANG_NEUTRAL,
+ HardErrorMessage->Status,
+ &MessageResource );
+ if( !NT_SUCCESS(Status) ) {
+ // WE HAVE TO DISPLAY HERE: "Unknown hard error"
+ if( ClientFileNameU.Buffer ) {
+ szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength+64);
+ wsprintfW(szxCaptionText, L"%s - %hs", ClientFileNameU.Buffer,
"Application Error");
+ } else {
+ szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, 64);
+ wsprintfW(szxCaptionText, L"System - Application Error");
+ }
+ MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 38);
+ wsprintfA(MessageBody, "Unknown hard error");
+ }
+ else {
+ LPSTR NtStatusString;
+ UNICODE_STRING MessageU;
+ ANSI_STRING MessageA;
+
+ RtlInitUnicodeString(&MessageU, (PWSTR)MessageResource->Text);
+ RtlUnicodeStringToAnsiString(&MessageA, &MessageU, TRUE);
+
+ USHORT CaptionSize = 0;
+ // check whether a caption exists
+ if( *MessageA.Buffer == '{' ) {
+ // get size of the caption
+ for( CaptionSize = 0; (CaptionSize < MessageA.Length) &&
('}' != MessageA.Buffer[CaptionSize]); CaptionSize++);
+
+ CaptionText = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
CaptionSize);
+ RtlCopyMemory(CaptionText, MessageA.Buffer+1, CaptionSize-1);
+ CaptionSize += 3; // "}\r\n" - 3
+
+ szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(wchar_t)*CaptionSize+ClientFileNameU.MaximumLength+128);
+ if( ClientFileNameU.Buffer ) {
+ wsprintfW(szxCaptionText, L"%s - %hs", ClientFileNameU.Buffer,
CaptionText);
+ } else {
+ wsprintfW(szxCaptionText, L"System - %hs", CaptionText);
+ }
+ RtlFreeHeap (RtlGetProcessHeap(), 0, CaptionText);
+ }
+ else {
+ if( ClientFileNameU.Buffer ) {
+ szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength);
+ wsprintfW(szxCaptionText, L"%s", ClientFileNameU.Buffer);
+ } else {
+ szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, 14); // 14 - "System\0\0"
+ wsprintfW(szxCaptionText, L"System");
+ }
+ }
+ if( STATUS_UNHANDLED_EXCEPTION == HardErrorMessage->Status )
+ {
+ PRTL_MESSAGE_RESOURCE_ENTRY MsgResException;
+ MessageBody = NULL;
+ Status = RtlFindMessage(
+ (PVOID)GetModuleHandle(TEXT("ntdll")),
+ (ULONG)RT_MESSAGETABLE,
+ LANG_NEUTRAL,
+ ParameterList[0],
+ &MsgResException);
+
+ if( NT_SUCCESS(Status) )
+ {
+ UNICODE_STRING ExcMessageU;
+ ANSI_STRING ExcMessageA;
+
+ RtlInitUnicodeString(&ExcMessageU, (PWSTR)MsgResException->Text);
+
+ RtlUnicodeStringToAnsiString(&ExcMessageA, &ExcMessageU, TRUE);
+
+ MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, MsgResException->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a
magic number I think it should be enough
+ if( STATUS_ACCESS_VIOLATION == ParameterList[0] ) {
+ LPSTR pOperationType;
+ if( ParameterList[2] ) pOperationType = "written";
+ else pOperationType = "read";
+ wsprintfA(MessageBody, ExcMessageA.Buffer, ParameterList[1],
ParameterList[3], pOperationType);
+ }
+ else if( STATUS_IN_PAGE_ERROR == ParameterList[0] ) {
+ wsprintfA(MessageBody, ExcMessageA.Buffer, ParameterList[1],
ParameterList[3], ParameterList[2]);
+ }
+ }
+ if( !MessageBody ) {
+ NtStatusString = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, MessageResource->Length-CaptionSize);
+ RtlCopyMemory(NtStatusString, MessageA.Buffer+CaptionSize,
(MessageResource->Length-CaptionSize)-1);
+
+ MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, MessageResource->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a
magic number I think it should be enough
+
+ wsprintfA(MessageBody, NtStatusString,
+ L"Unknown software exception",
+ ParameterList[0],
+ ParameterList[1]);
+
+ RtlFreeHeap (RtlGetProcessHeap(), 0, NtStatusString);
+ }
+ }
+ else
+ {
+ NtStatusString = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY, MessageResource->Length-CaptionSize);
+ RtlCopyMemory(NtStatusString, MessageA.Buffer+CaptionSize,
(MessageResource->Length-CaptionSize)-1);
+
+ MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
MessageResource->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a magic number I
think it should be enough
+
+ wsprintfA(MessageBody, NtStatusString,
+ ParameterList[0],
+ ParameterList[1],
+ ParameterList[2],
+ ParameterList[3]);
+
+ RtlFreeHeap (RtlGetProcessHeap(), 0, NtStatusString);
+ }
+ RtlFreeAnsiString(&MessageA);
+ }
+ if( ClientFileNameU.Buffer ) {
+ RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer);
+ }
+
+ szxMessageBody = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(wchar_t)*(strlen(MessageBody)+1));
+ wsprintfW(szxMessageBody, L"%hs", MessageBody);
+ RtlFreeHeap (RtlGetProcessHeap(), 0, MessageBody);
+
+ switch ( HardErrorMessage->ValidResponseOptions )
+ {
+ case OptionAbortRetryIgnore:
+ responce = MB_ABORTRETRYIGNORE;
+ break;
+
+ case OptionOk:
+ responce = MB_OK;
+ break;
+
+ case OptionOkCancel:
+ responce = MB_OKCANCEL;
+ break;
+
+ case OptionRetryCancel:
+ responce = MB_RETRYCANCEL;
+ break;
+
+ case OptionYesNo:
+ responce = MB_YESNO;
+ break;
+
+ case OptionYesNoCancel:
+ responce = MB_YESNOCANCEL;
+ break;
+
+ case OptionShutdownSystem:
+ // XZ??
+ break;
+
+ default:
+ DPRINT1("Wrong option: ValidResponseOptions = %d\n",
HardErrorMessage->ValidResponseOptions);
+ ASSERT(FALSE);
+ break;
+ }
+
+ // FIXME: We should not use MessageBox !!!!
+ MessageBoxResponse = MessageBoxW(0, szxMessageBody, szxCaptionText,
responce|MB_ICONERROR|MB_SYSTEMMODAL|MB_SETFOREGROUND);
+
+ RtlFreeHeap (RtlGetProcessHeap(), 0, szxMessageBody);
+ RtlFreeHeap (RtlGetProcessHeap(), 0, szxCaptionText);
+
+ switch( MessageBoxResponse )
+ {
+ case IDOK:
+ HardErrorMessage->Response = ResponseOk;
+ break;
+
+ case IDCANCEL:
+ HardErrorMessage->Response = ResponseCancel;
+ break;
+
+ case IDYES:
+ HardErrorMessage->Response = ResponseYes;
+ break;
+
+ case IDNO:
+ HardErrorMessage->Response = ResponseNo;
+ break;
+
+ case IDABORT:
+ HardErrorMessage->Response = ResponseAbort;
+ break;
+
+ case IDIGNORE:
+ HardErrorMessage->Response = ResponseIgnore;
+ break;
+
+ case IDRETRY:
+ HardErrorMessage->Response = ResponseRetry;
+ break;
+
+ case 10://IDTRYAGAIN:
+ HardErrorMessage->Response = ResponseTryAgain;
+ break;
+
+ case 11://IDCONTINUE:
+ HardErrorMessage->Response = ResponseContinue;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
return TRUE;
}