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_t);
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
),
164 if (!NT_SUCCESS(Status
))
167 /* Allocate a buffer for the string */
168 TempStringU
.MaximumLength
= ParamStringU
.Length
;
169 TempStringU
.Length
= ParamStringU
.Length
;
170 TempStringU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
172 TempStringU
.MaximumLength
);
174 if (!TempStringU
.Buffer
)
176 DPRINT1("Cannot allocate memory %u\n", TempStringU
.MaximumLength
);
177 Status
= STATUS_NO_MEMORY
;
180 /* Read the string buffer from the process memory */
181 Status
= NtReadVirtualMemory(hProcess
,
186 if (!NT_SUCCESS(Status
))
188 DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status
);
189 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
193 DPRINT("ParamString=\'%wZ\'\n", &TempStringU
);
195 /* Allocate a buffer for converted to ANSI string */
196 TempStringA
.MaximumLength
= RtlUnicodeStringToAnsiSize(&TempStringU
);
197 TempStringA
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
199 TempStringA
.MaximumLength
);
201 if (!TempStringA
.Buffer
)
203 DPRINT1("Cannot allocate memory %u\n", TempStringA
.MaximumLength
);
204 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
205 Status
= STATUS_NO_MEMORY
;
209 /* Convert string to ANSI and free temporary buffer */
210 Status
= RtlUnicodeStringToAnsiString(&TempStringA
, &TempStringU
, FALSE
);
211 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
212 if (!NT_SUCCESS(Status
))
214 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA
.Buffer
);
218 /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
219 Parameters
[nParam
] = (ULONG_PTR
)TempStringA
.Buffer
;
220 Size
+= TempStringU
.Length
;
224 /* It's not a unicode string */
225 Parameters
[nParam
] = HardErrorMessage
->Parameters
[nParam
];
229 if (!NT_SUCCESS(Status
))
231 UserpFreeStringParameters(Parameters
, HardErrorMessage
);
235 if (SizeOfAllUnicodeStrings
)
236 *SizeOfAllUnicodeStrings
= Size
;
244 OUT PUNICODE_STRING TextStringU
,
245 OUT PUNICODE_STRING CaptionStringU
,
246 IN PULONG_PTR Parameters
,
247 IN ULONG SizeOfStrings
,
248 IN PHARDERROR_MSG Message
,
252 UNICODE_STRING FileNameU
, TempStringU
, FormatU
;
254 PMESSAGE_RESOURCE_ENTRY MessageResource
;
256 ULONG Size
, ExceptionCode
;
258 /* Get the file name of the client process */
259 UserpGetClientFileName(&FileNameU
, hProcess
);
261 /* Check if we have a file name */
262 if (!FileNameU
.Buffer
)
265 RtlInitUnicodeString(&FileNameU
, L
"System");
268 /* Get text string of the error code */
269 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
270 (ULONG_PTR
)RT_MESSAGETABLE
,
275 if (NT_SUCCESS(Status
))
277 if (MessageResource
->Flags
)
279 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
280 FormatA
.Buffer
= NULL
;
284 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
285 RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
290 /* Fall back to hardcoded value */
291 RtlInitUnicodeString(&FormatU
, L
"Unknown Hard Error");
292 FormatA
.Buffer
= NULL
;
295 FormatString
= FormatU
.Buffer
;
297 /* Check whether a caption exists */
298 if (FormatString
[0] == L
'{')
300 /* Set caption start */
301 TempStringU
.Buffer
= ++FormatString
;
303 /* Get size of the caption */
304 for (Size
= 0; *FormatString
!= 0 && *FormatString
!= L
'}'; Size
++)
307 /* Skip '}', '\r', '\n' */
310 TempStringU
.Length
= Size
* sizeof(WCHAR
);
311 TempStringU
.MaximumLength
= TempStringU
.Length
;
315 /* FIXME: Set string based on severity */
316 RtlInitUnicodeString(&TempStringU
, L
"Application Error");
319 /* Calculate buffer length for the caption */
320 CaptionStringU
->MaximumLength
= FileNameU
.Length
+ TempStringU
.Length
+
323 /* Allocate a buffer for the caption */
324 CaptionStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
326 CaptionStringU
->MaximumLength
);
328 /* Append the file name, seperator and the caption text */
329 CaptionStringU
->Length
= 0;
330 RtlAppendUnicodeStringToString(CaptionStringU
, &FileNameU
);
331 RtlAppendUnicodeToString(CaptionStringU
, L
" - ");
332 RtlAppendUnicodeStringToString(CaptionStringU
, &TempStringU
);
334 /* Zero terminate the buffer */
335 CaptionStringU
->Buffer
[CaptionStringU
->Length
/ sizeof(WCHAR
)] = 0;
337 /* Free the file name buffer */
338 RtlFreeUnicodeString(&FileNameU
);
340 /* Check if this is an exception message */
341 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
343 ExceptionCode
= Parameters
[0];
345 /* Handle special cases */
346 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
)
348 Parameters
[0] = Parameters
[1];
349 Parameters
[1] = Parameters
[3];
350 if (Parameters
[2]) Parameters
[2] = (ULONG_PTR
)L
"written";
351 else 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
,
377 if (NT_SUCCESS(Status
))
379 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
381 if (MessageResource
->Flags
)
383 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
384 FormatA
.Buffer
= NULL
;
388 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
389 RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
391 FormatString
= FormatU
.Buffer
;
395 /* Fall back to hardcoded value */
396 Parameters
[2] = Parameters
[1];
397 Parameters
[1] = Parameters
[0];
398 Parameters
[0] = (ULONG_PTR
)L
"unknown software exception";
403 /* Calculate length of text buffer */
404 TextStringU
->MaximumLength
= FormatU
.Length
+ SizeOfStrings
+ 42 * sizeof(WCHAR
);
406 /* Allocate a buffer for the text */
407 TextStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
409 TextStringU
->MaximumLength
);
411 /* Wrap in SEH to protect from invalid string parameters */
414 /* Print the string into the buffer */
415 StringCbPrintfW(TextStringU
->Buffer
,
416 TextStringU
->MaximumLength
,
422 Status
= STATUS_SUCCESS
;
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
426 /* Set error and free buffers */
427 Status
= _SEH2_GetExceptionCode();
428 RtlFreeHeap(RtlGetProcessHeap(), 0, TextStringU
->Buffer
);
429 RtlFreeHeap(RtlGetProcessHeap(), 0, CaptionStringU
->Buffer
);
433 if (NT_SUCCESS(Status
))
435 TextStringU
->Length
= wcslen(TextStringU
->Buffer
) * sizeof(WCHAR
);
438 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
448 ULONG ValidResponseOptions
,
451 ULONG Type
, MessageBoxResponse
;
453 /* Set the message box type */
454 switch (ValidResponseOptions
)
456 case OptionAbortRetryIgnore
:
457 Type
= MB_ABORTRETRYIGNORE
;
465 case OptionRetryCancel
:
466 Type
= MB_RETRYCANCEL
;
471 case OptionYesNoCancel
:
472 Type
= MB_YESNOCANCEL
;
474 case OptionShutdownSystem
:
475 Type
= MB_RETRYCANCEL
; // FIXME???
477 /* Anything else is invalid */
479 return ResponseNotHandled
;
483 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
484 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
485 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
487 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
489 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
490 Text
, Caption
, Severity
, Type
);
492 /* Display a message box */
493 MessageBoxResponse
= MessageBoxW(0, Text
, Caption
, Type
);
495 /* Return response value */
496 switch (MessageBoxResponse
)
498 case IDOK
: return ResponseOk
;
499 case IDCANCEL
: return ResponseCancel
;
500 case IDYES
: return ResponseYes
;
501 case IDNO
: return ResponseNo
;
502 case IDABORT
: return ResponseAbort
;
503 case IDIGNORE
: return ResponseIgnore
;
504 case IDRETRY
: return ResponseRetry
;
505 case IDTRYAGAIN
: return ResponseTryAgain
;
506 case IDCONTINUE
: return ResponseContinue
;
509 return ResponseNotHandled
;
515 IN PCSR_THREAD ThreadData
,
516 IN PHARDERROR_MSG Message
)
519 PCSR_PROCESS ProcessData
= ThreadData
->Process
;
521 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
522 OBJECT_ATTRIBUTES ObjectAttributes
;
523 UNICODE_STRING TextU
, CaptionU
;
528 /* Default to not handled */
529 ASSERT(ProcessData
!= NULL
);
530 Message
->Response
= ResponseNotHandled
;
532 /* Make sure we don't have too many parameters */
533 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
534 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
536 /* Initialize object attributes */
537 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
539 /* Open client process */
540 Status
= NtOpenProcess(&hProcess
,
541 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
543 &Message
->h
.ClientId
);
545 if (!NT_SUCCESS(Status
))
547 DPRINT1("NtOpenProcess failed with code: %lx\n", Status
);
551 /* Capture all string parameters from the process memory */
552 Status
= UserpCaptureStringParameters(Parameters
, &Size
, Message
, hProcess
);
553 if (!NT_SUCCESS(Status
))
559 /* Format the caption and message box text */
560 Status
= UserpFormatMessages(&TextU
,
568 UserpFreeStringParameters(Parameters
, Message
);
571 if (!NT_SUCCESS(Status
))
576 /* Display the message box */
577 Message
->Response
= UserpMessageBox(TextU
.Buffer
,
579 Message
->ValidResponseOptions
,
580 (ULONG
)Message
->Status
>> 30);
582 RtlFreeUnicodeString(&TextU
);
583 RtlFreeUnicodeString(&CaptionU
);