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/incl... ============================================================================== --- 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/init... ============================================================================== --- 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/win3... ============================================================================== --- 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@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; }