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
);
443 UserpShowInformationBalloon(PWSTR Text
,
445 PHARDERROR_MSG Message
)
448 COPYDATASTRUCT CopyData
;
449 PBALLOON_HARD_ERROR_DATA pdata
;
450 DWORD dwSize
, cchText
, cchCaption
;
451 PWCHAR pText
, pCaption
;
454 hwnd
= GetTaskmanWindow();
457 DPRINT1("Failed to find Shell_TrayWnd\n");
461 cchText
= wcslen(Text
);
462 cchCaption
= wcslen(Caption
);
464 dwSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
465 dwSize
+= (cchText
+ 1) * sizeof(WCHAR
);
466 dwSize
+= (cchCaption
+ 1) * sizeof(WCHAR
);
468 pdata
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
471 DPRINT1("Failed to allocate balloon package\n");
475 pdata
->cbHeaderSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
476 pdata
->Status
= Message
->Status
;
477 if (NT_SUCCESS(Message
->Status
))
478 pdata
->dwType
= MB_OK
;
479 else if (Message
->Status
== STATUS_SERVICE_NOTIFICATION
)
480 pdata
->dwType
= Message
->Parameters
[2];
482 pdata
->dwType
= MB_ICONINFORMATION
;
483 pdata
->TitleOffset
= pdata
->cbHeaderSize
;
484 pdata
->MessageOffset
= pdata
->TitleOffset
;
485 pdata
->MessageOffset
+= (cchCaption
+ 1) * sizeof(WCHAR
);
486 pCaption
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->TitleOffset
);
487 pText
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->MessageOffset
);
488 wcscpy(pCaption
, Caption
);
491 CopyData
.dwData
= RegisterWindowMessageW(L
"HardError");
492 CopyData
.cbData
= dwSize
;
493 CopyData
.lpData
= pdata
;
497 ret
= SendMessageTimeoutW(hwnd
, WM_COPYDATA
, 0, (LPARAM
)&CopyData
,
498 SMTO_NORMAL
| SMTO_ABORTIFHUNG
, 3000, &dwResult
);
500 RtlFreeHeap(RtlGetProcessHeap(), 0, pdata
);
502 return (ret
&& dwResult
) ? TRUE
: FALSE
;
510 ULONG ValidResponseOptions
,
513 ULONG Type
, MessageBoxResponse
;
515 /* Set the message box type */
516 switch (ValidResponseOptions
)
518 case OptionAbortRetryIgnore
:
519 Type
= MB_ABORTRETRYIGNORE
;
527 case OptionRetryCancel
:
528 Type
= MB_RETRYCANCEL
;
533 case OptionYesNoCancel
:
534 Type
= MB_YESNOCANCEL
;
536 case OptionShutdownSystem
:
537 Type
= MB_RETRYCANCEL
; // FIXME???
541 * At that point showing the balloon failed. Is that correct?
543 Type
= MB_OK
; // FIXME!
545 case OptionCancelTryContinue
:
546 Type
= MB_CANCELTRYCONTINUE
;
549 /* Anything else is invalid */
552 DPRINT1("Unknown ValidResponseOptions = %d\n", ValidResponseOptions
);
553 return ResponseNotHandled
;
558 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
559 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
560 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
562 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
564 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
565 Text
, Caption
, Severity
, Type
);
567 /* Display a message box */
568 MessageBoxResponse
= MessageBoxW(NULL
, Text
, Caption
, Type
);
570 /* Return response value */
571 switch (MessageBoxResponse
)
573 case IDOK
: return ResponseOk
;
574 case IDCANCEL
: return ResponseCancel
;
575 case IDYES
: return ResponseYes
;
576 case IDNO
: return ResponseNo
;
577 case IDABORT
: return ResponseAbort
;
578 case IDIGNORE
: return ResponseIgnore
;
579 case IDRETRY
: return ResponseRetry
;
580 case IDTRYAGAIN
: return ResponseTryAgain
;
581 case IDCONTINUE
: return ResponseContinue
;
584 return ResponseNotHandled
;
590 IN PCSR_THREAD ThreadData
,
591 IN PHARDERROR_MSG Message
)
593 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
594 OBJECT_ATTRIBUTES ObjectAttributes
;
595 UNICODE_STRING TextU
, CaptionU
;
600 ASSERT(ThreadData
->Process
!= NULL
);
602 /* Default to not handled */
603 Message
->Response
= ResponseNotHandled
;
605 /* Make sure we don't have too many parameters */
606 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
607 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
609 /* Initialize object attributes */
610 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
612 /* Open client process */
613 Status
= NtOpenProcess(&hProcess
,
614 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
616 &Message
->h
.ClientId
);
617 if (!NT_SUCCESS(Status
))
619 DPRINT1("NtOpenProcess failed with code: %lx\n", Status
);
623 /* Capture all string parameters from the process memory */
624 Status
= UserpCaptureStringParameters(Parameters
, &Size
, Message
, hProcess
);
625 if (!NT_SUCCESS(Status
))
631 /* Format the caption and message box text */
632 Status
= UserpFormatMessages(&TextU
,
640 UserpFreeStringParameters(Parameters
, Message
);
643 if (!NT_SUCCESS(Status
))
648 if (Message
->ValidResponseOptions
== OptionOkNoWait
)
650 /* Display the balloon */
651 if (UserpShowInformationBalloon(TextU
.Buffer
,
655 Message
->Response
= ResponseOk
;
656 RtlFreeUnicodeString(&TextU
);
657 RtlFreeUnicodeString(&CaptionU
);
662 /* Display the message box */
663 Message
->Response
= UserpMessageBox(TextU
.Buffer
,
665 Message
->ValidResponseOptions
,
666 (ULONG
)Message
->Status
>> 30);
668 RtlFreeUnicodeString(&TextU
);
669 RtlFreeUnicodeString(&CaptionU
);