2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS User API Server DLL
4 * FILE: win32ss/user/winsrv/harderror.c
6 * PROGRAMMERS: Dmitry Philippov (shedon@mail.ru)
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES *******************************************************************/
22 /* FUNCTIONS ******************************************************************/
26 CsrpGetClientFileName(
27 OUT PUNICODE_STRING ClientFileNameU
,
30 PLIST_ENTRY ModuleListHead
;
32 PLDR_DATA_TABLE_ENTRY Module
;
34 PROCESS_BASIC_INFORMATION ClientBasicInfo
;
35 LDR_DATA_TABLE_ENTRY ModuleData
;
40 /* Initialize string */
41 ClientFileNameU
->MaximumLength
= 0;
42 ClientFileNameU
->Length
= 0;
43 ClientFileNameU
->Buffer
= NULL
;
45 /* Query process information */
46 Status
= NtQueryInformationProcess(hProcess
,
47 ProcessBasicInformation
,
49 sizeof(ClientBasicInfo
),
51 if (!NT_SUCCESS(Status
)) return Status
;
53 Peb
= ClientBasicInfo
.PebBaseAddress
;
54 if (!Peb
) return STATUS_UNSUCCESSFUL
;
56 Status
= NtReadVirtualMemory(hProcess
, &Peb
->Ldr
, &Ldr
, sizeof(Ldr
), NULL
);
57 if (!NT_SUCCESS(Status
)) return Status
;
59 ModuleListHead
= &Ldr
->InLoadOrderModuleList
;
60 Status
= NtReadVirtualMemory(hProcess
,
61 &ModuleListHead
->Flink
,
65 if (!NT_SUCCESS(Status
)) return Status
;
67 if (Entry
== ModuleListHead
) return STATUS_UNSUCCESSFUL
;
69 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
71 Status
= NtReadVirtualMemory(hProcess
,
76 if (!NT_SUCCESS(Status
)) return Status
;
78 Status
= NtReadVirtualMemory(hProcess
,
79 &Peb
->ImageBaseAddress
,
81 sizeof(ClientDllBase
),
83 if (!NT_SUCCESS(Status
)) return Status
;
85 if (ClientDllBase
!= ModuleData
.DllBase
) return STATUS_UNSUCCESSFUL
;
87 ClientFileNameU
->MaximumLength
= ModuleData
.BaseDllName
.MaximumLength
;
88 ClientFileNameU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
90 ClientFileNameU
->MaximumLength
);
92 Status
= NtReadVirtualMemory(hProcess
,
93 ModuleData
.BaseDllName
.Buffer
,
94 ClientFileNameU
->Buffer
,
95 ClientFileNameU
->MaximumLength
,
97 if (!NT_SUCCESS(Status
))
99 RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU
->Buffer
);
100 ClientFileNameU
->Buffer
= NULL
;
101 ClientFileNameU
->MaximumLength
= 0;
105 ClientFileNameU
->Length
= wcslen(ClientFileNameU
->Buffer
)*sizeof(wchar_t);
106 DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU
);
108 return STATUS_SUCCESS
;
113 CsrpFreeStringParameters(
114 IN OUT PULONG_PTR Parameters
,
115 IN PHARDERROR_MSG HardErrorMessage
)
119 /* Loop all parameters */
120 for (nParam
= 0; nParam
< HardErrorMessage
->NumberOfParameters
; nParam
++)
122 /* Check if the current parameter is a string */
123 if (HardErrorMessage
->UnicodeStringParameterMask
& (1 << nParam
) && Parameters
[nParam
])
125 /* Free the string buffer */
126 RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID
)Parameters
[nParam
]);
133 CsrpCaptureStringParameters(
134 OUT PULONG_PTR Parameters
,
135 OUT PULONG SizeOfAllUnicodeStrings
,
136 IN PHARDERROR_MSG HardErrorMessage
,
139 ULONG nParam
, Size
= 0;
140 NTSTATUS Status
= STATUS_SUCCESS
;
141 UNICODE_STRING TempStringU
, ParamStringU
;
142 ANSI_STRING TempStringA
;
144 if (SizeOfAllUnicodeStrings
)
145 *SizeOfAllUnicodeStrings
= 0;
147 /* Read all strings from client space */
148 for (nParam
= 0; nParam
< HardErrorMessage
->NumberOfParameters
; nParam
++)
150 Parameters
[nParam
] = 0;
152 /* Check if the current parameter is a unicode string */
153 if (HardErrorMessage
->UnicodeStringParameterMask
& (1 << nParam
))
155 /* Read the UNICODE_STRING from the process memory */
156 Status
= NtReadVirtualMemory(hProcess
,
157 (PVOID
)HardErrorMessage
->Parameters
[nParam
],
159 sizeof(ParamStringU
),
162 if (!NT_SUCCESS(Status
))
165 /* Allocate a buffer for the string */
166 TempStringU
.MaximumLength
= ParamStringU
.Length
;
167 TempStringU
.Length
= ParamStringU
.Length
;
168 TempStringU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
170 TempStringU
.MaximumLength
);
172 if (!TempStringU
.Buffer
)
174 DPRINT1("Cannot allocate memory %u\n", TempStringU
.MaximumLength
);
175 Status
= STATUS_NO_MEMORY
;
178 /* Read the string buffer from the process memory */
179 Status
= NtReadVirtualMemory(hProcess
,
184 if (!NT_SUCCESS(Status
))
186 DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status
);
187 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
191 DPRINT("ParamString=\'%wZ\'\n", &TempStringU
);
193 /* Allocate a buffer for converted to ANSI string */
194 TempStringA
.MaximumLength
= RtlUnicodeStringToAnsiSize(&TempStringU
);
195 TempStringA
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
197 TempStringA
.MaximumLength
);
199 if (!TempStringA
.Buffer
)
201 DPRINT1("Cannot allocate memory %u\n", TempStringA
.MaximumLength
);
202 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
203 Status
= STATUS_NO_MEMORY
;
207 /* Convert string to ANSI and free temporary buffer */
208 Status
= RtlUnicodeStringToAnsiString(&TempStringA
, &TempStringU
, FALSE
);
209 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
210 if (!NT_SUCCESS(Status
))
212 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA
.Buffer
);
216 /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
217 Parameters
[nParam
] = (ULONG_PTR
)TempStringA
.Buffer
;
218 Size
+= TempStringU
.Length
;
222 /* It's not a unicode string */
223 Parameters
[nParam
] = HardErrorMessage
->Parameters
[nParam
];
227 if (!NT_SUCCESS(Status
))
229 CsrpFreeStringParameters(Parameters
, HardErrorMessage
);
233 if (SizeOfAllUnicodeStrings
)
234 *SizeOfAllUnicodeStrings
= Size
;
242 OUT PUNICODE_STRING TextStringU
,
243 OUT PUNICODE_STRING CaptionStringU
,
244 IN PULONG_PTR Parameters
,
245 IN ULONG SizeOfStrings
,
246 IN PHARDERROR_MSG Message
,
250 UNICODE_STRING FileNameU
, TempStringU
, FormatU
;
252 PMESSAGE_RESOURCE_ENTRY MessageResource
;
254 ULONG Size
, ExceptionCode
;
256 /* Get the file name of the client process */
257 CsrpGetClientFileName(&FileNameU
, hProcess
);
259 /* Check if we have a file name */
260 if (!FileNameU
.Buffer
)
263 RtlInitUnicodeString(&FileNameU
, L
"System");
266 /* Get text string of the error code */
267 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
268 (ULONG_PTR
)RT_MESSAGETABLE
,
273 if (NT_SUCCESS(Status
))
275 if (MessageResource
->Flags
)
277 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
278 FormatA
.Buffer
= NULL
;
282 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
283 RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
288 /* Fall back to hardcoded value */
289 RtlInitUnicodeString(&FormatU
, L
"Unknown Hard Error");
290 FormatA
.Buffer
= NULL
;
293 FormatString
= FormatU
.Buffer
;
295 /* Check whether a caption exists */
296 if (FormatString
[0] == L
'{')
298 /* Set caption start */
299 TempStringU
.Buffer
= ++FormatString
;
301 /* Get size of the caption */
302 for (Size
= 0; *FormatString
!= 0 && *FormatString
!= L
'}'; Size
++)
305 /* Skip '}', '\r', '\n' */
308 TempStringU
.Length
= Size
* sizeof(WCHAR
);
309 TempStringU
.MaximumLength
= TempStringU
.Length
;
313 /* FIXME: Set string based on severity */
314 RtlInitUnicodeString(&TempStringU
, L
"Application Error");
317 /* Calculate buffer length for the caption */
318 CaptionStringU
->MaximumLength
= FileNameU
.Length
+ TempStringU
.Length
+
321 /* Allocate a buffer for the caption */
322 CaptionStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
324 CaptionStringU
->MaximumLength
);
326 /* Append the file name, seperator and the caption text */
327 CaptionStringU
->Length
= 0;
328 RtlAppendUnicodeStringToString(CaptionStringU
, &FileNameU
);
329 RtlAppendUnicodeToString(CaptionStringU
, L
" - ");
330 RtlAppendUnicodeStringToString(CaptionStringU
, &TempStringU
);
332 /* Zero terminate the buffer */
333 CaptionStringU
->Buffer
[CaptionStringU
->Length
/ sizeof(WCHAR
)] = 0;
335 /* Free the file name buffer */
336 RtlFreeUnicodeString(&FileNameU
);
338 /* Check if this is an exception message */
339 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
341 ExceptionCode
= Parameters
[0];
343 /* Handle special cases */
344 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
)
346 Parameters
[0] = Parameters
[1];
347 Parameters
[1] = Parameters
[3];
348 if (Parameters
[2]) Parameters
[2] = (ULONG_PTR
)L
"written";
349 else Parameters
[2] = (ULONG_PTR
)L
"read";
350 MessageResource
= NULL
;
352 else if (ExceptionCode
== STATUS_IN_PAGE_ERROR
)
354 Parameters
[0] = Parameters
[1];
355 Parameters
[1] = Parameters
[3];
356 MessageResource
= NULL
;
360 /* Fall back to hardcoded value */
361 Parameters
[2] = Parameters
[1];
362 Parameters
[1] = Parameters
[0];
363 Parameters
[0] = (ULONG_PTR
)L
"unknown software exception";
366 if (!MessageResource
)
368 /* Get text string of the exception code */
369 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
370 (ULONG_PTR
)RT_MESSAGETABLE
,
375 if (NT_SUCCESS(Status
))
377 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
379 if (MessageResource
->Flags
)
381 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
382 FormatA
.Buffer
= NULL
;
386 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
387 RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
389 FormatString
= FormatU
.Buffer
;
393 /* Fall back to hardcoded value */
394 Parameters
[2] = Parameters
[1];
395 Parameters
[1] = Parameters
[0];
396 Parameters
[0] = (ULONG_PTR
)L
"unknown software exception";
401 /* Calculate length of text buffer */
402 TextStringU
->MaximumLength
= FormatU
.Length
+ SizeOfStrings
+ 42 * sizeof(WCHAR
);
404 /* Allocate a buffer for the text */
405 TextStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
407 TextStringU
->MaximumLength
);
409 /* Wrap in SEH to protect from invalid string parameters */
412 /* Print the string into the buffer */
413 StringCbPrintfW(TextStringU
->Buffer
,
414 TextStringU
->MaximumLength
,
420 Status
= STATUS_SUCCESS
;
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
424 /* Set error and free buffers */
425 Status
= _SEH2_GetExceptionCode();
426 RtlFreeHeap(RtlGetProcessHeap(), 0, TextStringU
->Buffer
);
427 RtlFreeHeap(RtlGetProcessHeap(), 0, CaptionStringU
->Buffer
);
431 if (NT_SUCCESS(Status
))
433 TextStringU
->Length
= wcslen(TextStringU
->Buffer
) * sizeof(WCHAR
);
436 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
446 ULONG ValidResponseOptions
,
449 ULONG Type
, MessageBoxResponse
;
451 /* Set the message box type */
452 switch (ValidResponseOptions
)
454 case OptionAbortRetryIgnore
:
455 Type
= MB_ABORTRETRYIGNORE
;
463 case OptionRetryCancel
:
464 Type
= MB_RETRYCANCEL
;
469 case OptionYesNoCancel
:
470 Type
= MB_YESNOCANCEL
;
472 case OptionShutdownSystem
:
473 Type
= MB_RETRYCANCEL
; // FIXME???
475 /* Anything else is invalid */
477 return ResponseNotHandled
;
481 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
482 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
483 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
485 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
487 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
488 Text
, Caption
, Severity
, Type
);
490 /* Display a message box */
491 MessageBoxResponse
= MessageBoxW(0, Text
, Caption
, Type
);
493 /* Return response value */
494 switch (MessageBoxResponse
)
496 case IDOK
: return ResponseOk
;
497 case IDCANCEL
: return ResponseCancel
;
498 case IDYES
: return ResponseYes
;
499 case IDNO
: return ResponseNo
;
500 case IDABORT
: return ResponseAbort
;
501 case IDIGNORE
: return ResponseIgnore
;
502 case IDRETRY
: return ResponseRetry
;
503 case IDTRYAGAIN
: return ResponseTryAgain
;
504 case IDCONTINUE
: return ResponseContinue
;
507 return ResponseNotHandled
;
513 IN PCSR_THREAD ThreadData
,
514 IN PHARDERROR_MSG Message
)
517 PCSR_PROCESS ProcessData
= ThreadData
->Process
;
519 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
520 OBJECT_ATTRIBUTES ObjectAttributes
;
521 UNICODE_STRING TextU
, CaptionU
;
526 /* Default to not handled */
527 ASSERT(ProcessData
!= NULL
);
528 Message
->Response
= ResponseNotHandled
;
530 /* Make sure we don't have too many parameters */
531 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
532 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
534 /* Initialize object attributes */
535 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
537 /* Open client process */
538 Status
= NtOpenProcess(&hProcess
,
539 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
541 &Message
->h
.ClientId
);
543 if (!NT_SUCCESS(Status
))
545 DPRINT1("NtOpenProcess failed with code: %lx\n", Status
);
549 /* Capture all string parameters from the process memory */
550 Status
= CsrpCaptureStringParameters(Parameters
, &Size
, Message
, hProcess
);
551 if (!NT_SUCCESS(Status
))
557 /* Format the caption and message box text */
558 Status
= CsrpFormatMessages(&TextU
,
566 CsrpFreeStringParameters(Parameters
, Message
);
569 if (!NT_SUCCESS(Status
))
574 /* Display the message box */
575 Message
->Response
= CsrpMessageBox(TextU
.Buffer
,
577 Message
->ValidResponseOptions
,
578 (ULONG
)Message
->Status
>> 30);
580 RtlFreeUnicodeString(&TextU
);
581 RtlFreeUnicodeString(&CaptionU
);