2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS User API Server DLL
4 * FILE: win32ss/user/winsrv/usersrv/harderror.c
6 * PROGRAMMERS: Dmitry Philippov (shedon@mail.ru)
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES *******************************************************************/
14 #include <ndk/mmfuncs.h>
15 #include <pseh/pseh2.h>
24 /* FUNCTIONS ******************************************************************/
28 UserpGetClientFileName(
29 OUT PUNICODE_STRING ClientFileNameU
,
32 PLIST_ENTRY ModuleListHead
;
34 PLDR_DATA_TABLE_ENTRY Module
;
36 PROCESS_BASIC_INFORMATION ClientBasicInfo
;
37 LDR_DATA_TABLE_ENTRY ModuleData
;
42 /* Initialize string */
43 ClientFileNameU
->MaximumLength
= 0;
44 ClientFileNameU
->Length
= 0;
45 ClientFileNameU
->Buffer
= NULL
;
47 /* Query process information */
48 Status
= NtQueryInformationProcess(hProcess
,
49 ProcessBasicInformation
,
51 sizeof(ClientBasicInfo
),
53 if (!NT_SUCCESS(Status
)) return Status
;
55 Peb
= ClientBasicInfo
.PebBaseAddress
;
56 if (!Peb
) return STATUS_UNSUCCESSFUL
;
58 Status
= NtReadVirtualMemory(hProcess
, &Peb
->Ldr
, &Ldr
, sizeof(Ldr
), NULL
);
59 if (!NT_SUCCESS(Status
)) return Status
;
61 ModuleListHead
= &Ldr
->InLoadOrderModuleList
;
62 Status
= NtReadVirtualMemory(hProcess
,
63 &ModuleListHead
->Flink
,
67 if (!NT_SUCCESS(Status
)) return Status
;
69 if (Entry
== ModuleListHead
) return STATUS_UNSUCCESSFUL
;
71 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
73 Status
= NtReadVirtualMemory(hProcess
,
78 if (!NT_SUCCESS(Status
)) return Status
;
80 Status
= NtReadVirtualMemory(hProcess
,
81 &Peb
->ImageBaseAddress
,
83 sizeof(ClientDllBase
),
85 if (!NT_SUCCESS(Status
)) return Status
;
87 if (ClientDllBase
!= ModuleData
.DllBase
) return STATUS_UNSUCCESSFUL
;
89 ClientFileNameU
->MaximumLength
= ModuleData
.BaseDllName
.MaximumLength
;
90 ClientFileNameU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
92 ClientFileNameU
->MaximumLength
);
94 Status
= NtReadVirtualMemory(hProcess
,
95 ModuleData
.BaseDllName
.Buffer
,
96 ClientFileNameU
->Buffer
,
97 ClientFileNameU
->MaximumLength
,
99 if (!NT_SUCCESS(Status
))
101 RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU
->Buffer
);
102 ClientFileNameU
->Buffer
= NULL
;
103 ClientFileNameU
->MaximumLength
= 0;
107 ClientFileNameU
->Length
= wcslen(ClientFileNameU
->Buffer
) * sizeof(WCHAR
);
108 DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU
);
110 return STATUS_SUCCESS
;
115 UserpFreeStringParameters(
116 IN OUT PULONG_PTR Parameters
,
117 IN PHARDERROR_MSG HardErrorMessage
)
121 /* Loop all parameters */
122 for (nParam
= 0; nParam
< HardErrorMessage
->NumberOfParameters
; nParam
++)
124 /* Check if the current parameter is a string */
125 if (HardErrorMessage
->UnicodeStringParameterMask
& (1 << nParam
) && Parameters
[nParam
])
127 /* Free the string buffer */
128 RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID
)Parameters
[nParam
]);
135 UserpCaptureStringParameters(
136 OUT PULONG_PTR Parameters
,
137 OUT PULONG SizeOfAllUnicodeStrings
,
138 IN PHARDERROR_MSG HardErrorMessage
,
141 ULONG nParam
, Size
= 0;
142 NTSTATUS Status
= STATUS_SUCCESS
;
143 UNICODE_STRING TempStringU
, ParamStringU
;
144 ANSI_STRING TempStringA
;
146 if (SizeOfAllUnicodeStrings
)
147 *SizeOfAllUnicodeStrings
= 0;
149 /* Read all strings from client space */
150 for (nParam
= 0; nParam
< HardErrorMessage
->NumberOfParameters
; nParam
++)
152 Parameters
[nParam
] = 0;
154 /* Check if the current parameter is a unicode string */
155 if (HardErrorMessage
->UnicodeStringParameterMask
& (1 << nParam
))
157 /* Read the UNICODE_STRING from the process memory */
158 Status
= NtReadVirtualMemory(hProcess
,
159 (PVOID
)HardErrorMessage
->Parameters
[nParam
],
161 sizeof(ParamStringU
),
163 if (!NT_SUCCESS(Status
))
166 /* Allocate a buffer for the string */
167 TempStringU
.MaximumLength
= ParamStringU
.Length
;
168 TempStringU
.Length
= ParamStringU
.Length
;
169 TempStringU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
171 TempStringU
.MaximumLength
);
173 if (!TempStringU
.Buffer
)
175 DPRINT1("Cannot allocate memory %u\n", TempStringU
.MaximumLength
);
176 Status
= STATUS_NO_MEMORY
;
179 /* Read the string buffer from the process memory */
180 Status
= NtReadVirtualMemory(hProcess
,
185 if (!NT_SUCCESS(Status
))
187 DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status
);
188 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
192 DPRINT("ParamString=\'%wZ\'\n", &TempStringU
);
194 /* Allocate a buffer for converted to ANSI string */
195 TempStringA
.MaximumLength
= RtlUnicodeStringToAnsiSize(&TempStringU
);
196 TempStringA
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
198 TempStringA
.MaximumLength
);
200 if (!TempStringA
.Buffer
)
202 DPRINT1("Cannot allocate memory %u\n", TempStringA
.MaximumLength
);
203 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
204 Status
= STATUS_NO_MEMORY
;
208 /* Convert string to ANSI and free temporary buffer */
209 Status
= RtlUnicodeStringToAnsiString(&TempStringA
, &TempStringU
, FALSE
);
210 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
211 if (!NT_SUCCESS(Status
))
213 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA
.Buffer
);
217 /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
218 Parameters
[nParam
] = (ULONG_PTR
)TempStringA
.Buffer
;
219 Size
+= TempStringU
.Length
;
223 /* It's not a unicode string */
224 Parameters
[nParam
] = HardErrorMessage
->Parameters
[nParam
];
228 if (!NT_SUCCESS(Status
))
230 UserpFreeStringParameters(Parameters
, HardErrorMessage
);
234 if (SizeOfAllUnicodeStrings
)
235 *SizeOfAllUnicodeStrings
= Size
;
243 OUT PUNICODE_STRING TextStringU
,
244 OUT PUNICODE_STRING CaptionStringU
,
245 IN PULONG_PTR Parameters
,
246 IN ULONG SizeOfStrings
,
247 IN PHARDERROR_MSG Message
,
251 UNICODE_STRING FileNameU
, TempStringU
, FormatU
;
253 PMESSAGE_RESOURCE_ENTRY MessageResource
;
255 ULONG Size
, ExceptionCode
;
257 /* Get the file name of the client process */
258 UserpGetClientFileName(&FileNameU
, hProcess
);
260 /* Check if we have a file name */
261 if (!FileNameU
.Buffer
)
264 RtlInitUnicodeString(&FileNameU
, L
"System");
267 /* Get text string of the error code */
268 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
269 (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];
349 Parameters
[2] = (ULONG_PTR
)L
"written";
351 Parameters
[2] = (ULONG_PTR
)L
"read";
352 MessageResource
= NULL
;
354 else if (ExceptionCode
== STATUS_IN_PAGE_ERROR
)
356 Parameters
[0] = Parameters
[1];
357 Parameters
[1] = Parameters
[3];
358 MessageResource
= NULL
;
362 /* Fall back to hardcoded value */
363 Parameters
[2] = Parameters
[1];
364 Parameters
[1] = Parameters
[0];
365 Parameters
[0] = (ULONG_PTR
)L
"unknown software exception";
368 if (!MessageResource
)
370 /* Get text string of the exception code */
371 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
372 (ULONG_PTR
)RT_MESSAGETABLE
,
376 if (NT_SUCCESS(Status
))
378 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
380 if (MessageResource
->Flags
)
382 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
383 FormatA
.Buffer
= NULL
;
387 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
388 RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
390 FormatString
= FormatU
.Buffer
;
394 /* Fall back to hardcoded value */
395 Parameters
[2] = Parameters
[1];
396 Parameters
[1] = Parameters
[0];
397 Parameters
[0] = (ULONG_PTR
)L
"unknown software exception";
402 /* Calculate length of text buffer */
403 TextStringU
->MaximumLength
= FormatU
.Length
+ SizeOfStrings
+ 42 * sizeof(WCHAR
);
405 /* Allocate a buffer for the text */
406 TextStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
408 TextStringU
->MaximumLength
);
410 /* Wrap in SEH to protect from invalid string parameters */
413 /* Print the string into the buffer */
414 StringCbPrintfW(TextStringU
->Buffer
,
415 TextStringU
->MaximumLength
,
421 Status
= STATUS_SUCCESS
;
423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
425 /* Set error and free buffers */
426 Status
= _SEH2_GetExceptionCode();
427 RtlFreeHeap(RtlGetProcessHeap(), 0, TextStringU
->Buffer
);
428 RtlFreeHeap(RtlGetProcessHeap(), 0, CaptionStringU
->Buffer
);
432 if (NT_SUCCESS(Status
))
434 TextStringU
->Length
= wcslen(TextStringU
->Buffer
) * sizeof(WCHAR
);
437 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
447 ULONG ValidResponseOptions
,
450 ULONG Type
, MessageBoxResponse
;
452 /* Set the message box type */
453 switch (ValidResponseOptions
)
455 case OptionAbortRetryIgnore
:
456 Type
= MB_ABORTRETRYIGNORE
;
464 case OptionRetryCancel
:
465 Type
= MB_RETRYCANCEL
;
470 case OptionYesNoCancel
:
471 Type
= MB_YESNOCANCEL
;
473 case OptionShutdownSystem
:
474 Type
= MB_RETRYCANCEL
; // FIXME???
478 * This gives a balloon notification.
479 * See rostests/kmtests/ntos_ex/ExHardError.c
481 Type
= MB_YESNO
; // FIXME!
483 case OptionCancelTryContinue
:
484 Type
= MB_CANCELTRYCONTINUE
;
487 /* Anything else is invalid */
490 DPRINT1("Unknown ValidResponseOptions = %d\n", ValidResponseOptions
);
491 return ResponseNotHandled
;
496 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
497 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
498 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
500 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
502 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
503 Text
, Caption
, Severity
, Type
);
505 /* Display a message box */
506 MessageBoxResponse
= MessageBoxW(NULL
, Text
, Caption
, Type
);
508 /* Return response value */
509 switch (MessageBoxResponse
)
511 case IDOK
: return ResponseOk
;
512 case IDCANCEL
: return ResponseCancel
;
513 case IDYES
: return ResponseYes
;
514 case IDNO
: return ResponseNo
;
515 case IDABORT
: return ResponseAbort
;
516 case IDIGNORE
: return ResponseIgnore
;
517 case IDRETRY
: return ResponseRetry
;
518 case IDTRYAGAIN
: return ResponseTryAgain
;
519 case IDCONTINUE
: return ResponseContinue
;
522 return ResponseNotHandled
;
528 IN PCSR_THREAD ThreadData
,
529 IN PHARDERROR_MSG Message
)
531 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
532 OBJECT_ATTRIBUTES ObjectAttributes
;
533 UNICODE_STRING TextU
, CaptionU
;
538 ASSERT(ThreadData
->Process
!= NULL
);
540 /* Default to not handled */
541 Message
->Response
= ResponseNotHandled
;
543 /* Make sure we don't have too many parameters */
544 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
545 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
547 /* Initialize object attributes */
548 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
550 /* Open client process */
551 Status
= NtOpenProcess(&hProcess
,
552 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
554 &Message
->h
.ClientId
);
555 if (!NT_SUCCESS(Status
))
557 DPRINT1("NtOpenProcess failed with code: %lx\n", Status
);
561 /* Capture all string parameters from the process memory */
562 Status
= UserpCaptureStringParameters(Parameters
, &Size
, Message
, hProcess
);
563 if (!NT_SUCCESS(Status
))
569 /* Format the caption and message box text */
570 Status
= UserpFormatMessages(&TextU
,
578 UserpFreeStringParameters(Parameters
, Message
);
581 if (!NT_SUCCESS(Status
))
586 /* Display the message box */
587 Message
->Response
= UserpMessageBox(TextU
.Buffer
,
589 Message
->ValidResponseOptions
,
590 (ULONG
)Message
->Status
>> 30);
592 RtlFreeUnicodeString(&TextU
);
593 RtlFreeUnicodeString(&CaptionU
);