2 * PROJECT: ReactOS User API Server DLL
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Hard errors support.
5 * COPYRIGHT: Copyright 2007-2018 Dmitry Philippov (shedon@mail.ru)
6 * Copyright 2010-2018 Timo Kreuzer (timo.kreuzer@reactos.org)
7 * Copyright 2012-2018 Hermes Belusca-Maito
8 * Copyright 2018 Giannis Adamopoulos
11 /* INCLUDES *******************************************************************/
15 #define NTOS_MODE_USER
16 #include <ndk/mmfuncs.h>
18 #include <undocelfapi.h>
19 #include <ntstrsafe.h>
27 /* FUNCTIONS ******************************************************************/
29 /* Cache for the localized hard-error message box strings */
30 LANGID g_CurrentUserLangId
= 0;
31 UNICODE_STRING g_SuccessU
= {0, 0, NULL
};
32 UNICODE_STRING g_InformationU
= {0, 0, NULL
};
33 UNICODE_STRING g_WarningU
= {0, 0, NULL
};
34 UNICODE_STRING g_ErrorU
= {0, 0, NULL
};
35 UNICODE_STRING g_SystemProcessU
= {0, 0, NULL
};
36 UNICODE_STRING g_OKTerminateU
= {0, 0, NULL
};
37 UNICODE_STRING g_CancelDebugU
= {0, 0, NULL
};
41 IN HINSTANCE hInstance OPTIONAL
,
43 OUT PUNICODE_STRING pUnicodeString
,
44 IN PCWSTR pDefaultString
)
48 /* Try to load the string from the resource */
49 Length
= LoadStringW(hInstance
, uID
, (LPWSTR
)&pUnicodeString
->Buffer
, 0);
52 /* If the resource string was not found, use the fallback default one */
53 RtlInitUnicodeString(pUnicodeString
, pDefaultString
);
57 /* Set the string length (not NULL-terminated!) */
58 pUnicodeString
->MaximumLength
= (USHORT
)(Length
* sizeof(WCHAR
));
59 pUnicodeString
->Length
= pUnicodeString
->MaximumLength
;
78 UserpGetClientFileName(
79 OUT PUNICODE_STRING ClientFileNameU
,
82 PLIST_ENTRY ModuleListHead
;
84 PLDR_DATA_TABLE_ENTRY Module
;
86 PROCESS_BASIC_INFORMATION ClientBasicInfo
;
87 LDR_DATA_TABLE_ENTRY ModuleData
;
92 /* Initialize string */
93 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
95 /* Query process information */
96 Status
= NtQueryInformationProcess(hProcess
,
97 ProcessBasicInformation
,
99 sizeof(ClientBasicInfo
),
101 if (!NT_SUCCESS(Status
)) return Status
;
103 /* Locate the process loader data table and retrieve its name from it */
105 Peb
= ClientBasicInfo
.PebBaseAddress
;
106 if (!Peb
) return STATUS_UNSUCCESSFUL
;
108 Status
= NtReadVirtualMemory(hProcess
, &Peb
->Ldr
, &Ldr
, sizeof(Ldr
), NULL
);
109 if (!NT_SUCCESS(Status
)) return Status
;
111 ModuleListHead
= &Ldr
->InLoadOrderModuleList
;
112 Status
= NtReadVirtualMemory(hProcess
,
113 &ModuleListHead
->Flink
,
117 if (!NT_SUCCESS(Status
)) return Status
;
119 if (Entry
== ModuleListHead
) return STATUS_UNSUCCESSFUL
;
121 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
123 Status
= NtReadVirtualMemory(hProcess
,
128 if (!NT_SUCCESS(Status
)) return Status
;
130 Status
= NtReadVirtualMemory(hProcess
,
131 &Peb
->ImageBaseAddress
,
133 sizeof(ClientDllBase
),
135 if (!NT_SUCCESS(Status
)) return Status
;
137 if (ClientDllBase
!= ModuleData
.DllBase
) return STATUS_UNSUCCESSFUL
;
139 ClientFileNameU
->MaximumLength
= ModuleData
.BaseDllName
.MaximumLength
;
140 ClientFileNameU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
142 ClientFileNameU
->MaximumLength
);
143 if (!ClientFileNameU
->Buffer
)
145 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
146 return STATUS_NO_MEMORY
;
149 Status
= NtReadVirtualMemory(hProcess
,
150 ModuleData
.BaseDllName
.Buffer
,
151 ClientFileNameU
->Buffer
,
152 ClientFileNameU
->MaximumLength
,
154 if (!NT_SUCCESS(Status
))
156 RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU
->Buffer
);
157 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
161 ClientFileNameU
->Length
= wcslen(ClientFileNameU
->Buffer
) * sizeof(WCHAR
);
162 DPRINT("ClientFileNameU = \'%wZ\'\n", &ClientFileNameU
);
164 return STATUS_SUCCESS
;
169 UserpFreeStringParameters(
170 IN OUT PULONG_PTR Parameters
,
171 IN PHARDERROR_MSG Message
)
175 /* Loop all parameters */
176 for (nParam
= 0; nParam
< Message
->NumberOfParameters
; ++nParam
)
178 /* Check if the current parameter is a string */
179 if ((Message
->UnicodeStringParameterMask
& (1 << nParam
)) && (Parameters
[nParam
] != 0))
181 /* Free the string buffer */
182 RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID
)Parameters
[nParam
]);
189 UserpCaptureStringParameters(
190 OUT PULONG_PTR Parameters
,
191 OUT PULONG SizeOfAllUnicodeStrings
,
192 IN PHARDERROR_MSG Message
,
193 IN HANDLE hProcess OPTIONAL
)
196 ULONG nParam
, Size
= 0;
197 UNICODE_STRING TempStringU
, ParamStringU
;
198 ANSI_STRING TempStringA
;
200 if (SizeOfAllUnicodeStrings
)
201 *SizeOfAllUnicodeStrings
= 0;
203 /* Read all strings from client space */
204 for (nParam
= 0; nParam
< Message
->NumberOfParameters
; ++nParam
)
206 Parameters
[nParam
] = 0;
208 /* Check if the current parameter is a unicode string */
209 if (Message
->UnicodeStringParameterMask
& (1 << nParam
))
211 /* Skip this string if we do not have a client process */
215 /* Read the UNICODE_STRING from the process memory */
216 Status
= NtReadVirtualMemory(hProcess
,
217 (PVOID
)Message
->Parameters
[nParam
],
219 sizeof(ParamStringU
),
221 if (!NT_SUCCESS(Status
))
223 /* We failed, skip this string */
224 DPRINT1("NtReadVirtualMemory(Message->Parameters) failed, Status 0x%lx, skipping.\n", Status
);
228 /* Allocate a buffer for the string */
229 TempStringU
.MaximumLength
= ParamStringU
.Length
;
230 TempStringU
.Length
= ParamStringU
.Length
;
231 TempStringU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
233 TempStringU
.MaximumLength
);
234 if (!TempStringU
.Buffer
)
236 /* We failed, skip this string */
237 DPRINT1("Cannot allocate memory with size %u, skipping.\n", TempStringU
.MaximumLength
);
241 /* Read the string buffer from the process memory */
242 Status
= NtReadVirtualMemory(hProcess
,
247 if (!NT_SUCCESS(Status
))
249 /* We failed, skip this string */
250 DPRINT1("NtReadVirtualMemory(ParamStringU) failed, Status 0x%lx, skipping.\n", Status
);
251 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
255 DPRINT("ParamString = \'%wZ\'\n", &TempStringU
);
257 /* Allocate a buffer for converted to ANSI string */
258 TempStringA
.MaximumLength
= RtlUnicodeStringToAnsiSize(&TempStringU
);
259 TempStringA
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
261 TempStringA
.MaximumLength
);
262 if (!TempStringA
.Buffer
)
264 /* We failed, skip this string */
265 DPRINT1("Cannot allocate memory with size %u, skipping.\n", TempStringA
.MaximumLength
);
266 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
270 /* Convert string to ANSI and free temporary buffer */
271 Status
= RtlUnicodeStringToAnsiString(&TempStringA
, &TempStringU
, FALSE
);
272 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
273 if (!NT_SUCCESS(Status
))
275 /* We failed, skip this string */
276 DPRINT1("RtlUnicodeStringToAnsiString() failed, Status 0x%lx, skipping.\n", Status
);
277 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA
.Buffer
);
281 /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
282 Parameters
[nParam
] = (ULONG_PTR
)TempStringA
.Buffer
;
283 Size
+= TempStringU
.Length
;
287 /* It's not a unicode string, just copy the parameter */
288 Parameters
[nParam
] = Message
->Parameters
[nParam
];
292 if (SizeOfAllUnicodeStrings
)
293 *SizeOfAllUnicodeStrings
= Size
;
299 OUT PUNICODE_STRING TextStringU
,
300 OUT PUNICODE_STRING CaptionStringU
,
301 IN PULONG_PTR Parameters
,
302 IN ULONG SizeOfStrings
,
303 IN PHARDERROR_MSG Message
,
304 IN HANDLE hProcess OPTIONAL
)
307 UNICODE_STRING FileNameU
, TempStringU
, WindowTitleU
, FormatU
, Format2U
;
308 ANSI_STRING FormatA
, Format2A
;
310 PMESSAGE_RESOURCE_ENTRY MessageResource
;
311 ULONG_PTR CapturedParameters
[MAXIMUM_HARDERROR_PARAMETERS
];
312 PWSTR FormatString
, pszBuffer
;
314 ULONG ExceptionCode
, Severity
;
317 /* Copy the Parameters array locally */
318 RtlCopyMemory(&CapturedParameters
, Parameters
, sizeof(CapturedParameters
));
320 /* Get the file name of the client process */
321 Status
= STATUS_SUCCESS
;
323 Status
= UserpGetClientFileName(&FileNameU
, hProcess
);
326 * Fall back to SYSTEM process if the client process handle
327 * was NULL or we failed retrieving a file name.
329 if (!hProcess
|| !NT_SUCCESS(Status
) || !FileNameU
.Buffer
)
332 FileNameU
= g_SystemProcessU
;
335 Severity
= (ULONG
)(Message
->Status
) >> 30;
337 /* Get text string of the error code */
338 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
339 (ULONG_PTR
)RT_MESSAGETABLE
,
343 if (NT_SUCCESS(Status
))
345 if (MessageResource
->Flags
)
347 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
348 FormatA
.Buffer
= NULL
;
352 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
353 /* Status = */ RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
358 /* Fall back to hardcoded value */
359 RtlInitUnicodeString(&FormatU
, L
"Unknown Hard Error");
360 FormatA
.Buffer
= NULL
;
363 FormatString
= FormatU
.Buffer
;
365 /* Check whether a caption exists */
366 if (FormatString
[0] == L
'{')
368 /* Set caption start */
369 TempStringU
.Buffer
= ++FormatString
;
371 /* Get size of the caption */
372 for (Size
= 0; *FormatString
!= UNICODE_NULL
&& *FormatString
!= L
'}'; Size
++)
375 /* Skip '}', '\r', '\n' */
378 TempStringU
.Length
= (USHORT
)(Size
* sizeof(WCHAR
));
379 TempStringU
.MaximumLength
= TempStringU
.Length
;
383 if (Severity
== STATUS_SEVERITY_SUCCESS
)
384 TempStringU
= g_SuccessU
;
385 else if (Severity
== STATUS_SEVERITY_INFORMATIONAL
)
386 TempStringU
= g_InformationU
;
387 else if (Severity
== STATUS_SEVERITY_WARNING
)
388 TempStringU
= g_WarningU
;
389 else if (Severity
== STATUS_SEVERITY_ERROR
)
390 TempStringU
= g_ErrorU
;
392 RtlInitEmptyUnicodeString(&TempStringU
, NULL
, 0);
395 /* Retrieve the window title of the client, if it has one */
396 RtlInitEmptyUnicodeString(&WindowTitleU
, NULL
, 0);
398 EnumThreadWindows(HandleToUlong(Message
->h
.ClientId
.UniqueThread
),
399 FindTopLevelWnd
, (LPARAM
)&hwndOwner
);
402 cchBuffer
= GetWindowTextLengthW(hwndOwner
);
405 cchBuffer
+= 3; // 2 characters for ": " and a NULL terminator.
406 WindowTitleU
.MaximumLength
= (USHORT
)(cchBuffer
* sizeof(WCHAR
));
407 WindowTitleU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
409 WindowTitleU
.MaximumLength
);
410 if (WindowTitleU
.Buffer
)
412 cchBuffer
= GetWindowTextW(hwndOwner
,
414 WindowTitleU
.MaximumLength
/ sizeof(WCHAR
));
415 WindowTitleU
.Length
= (USHORT
)(cchBuffer
* sizeof(WCHAR
));
416 RtlAppendUnicodeToString(&WindowTitleU
, L
": ");
420 RtlInitEmptyUnicodeString(&WindowTitleU
, NULL
, 0);
425 /* Calculate buffer length for the caption */
426 CaptionStringU
->MaximumLength
= WindowTitleU
.Length
+
427 FileNameU
.Length
+ TempStringU
.Length
+
428 3 * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
430 /* Allocate a buffer for the caption */
431 CaptionStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
433 CaptionStringU
->MaximumLength
);
434 if (!CaptionStringU
->Buffer
)
436 DPRINT1("Cannot allocate memory for CaptionStringU\n");
437 Status
= STATUS_NO_MEMORY
;
440 /* Append the file name, the separator and the caption text */
441 RtlStringCbPrintfW(CaptionStringU
->Buffer
,
442 CaptionStringU
->MaximumLength
,
444 &WindowTitleU
, &FileNameU
, &TempStringU
);
445 CaptionStringU
->Length
= wcslen(CaptionStringU
->Buffer
) * sizeof(WCHAR
);
447 /* Free string buffers if needed */
448 if (WindowTitleU
.Buffer
) RtlFreeUnicodeString(&WindowTitleU
);
449 if (hProcess
) RtlFreeUnicodeString(&FileNameU
);
451 // FIXME: What is 42 == ??
454 /* Check if this is an exception message */
455 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
457 ExceptionCode
= CapturedParameters
[0];
459 /* Get text string of the exception code */
460 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
461 (ULONG_PTR
)RT_MESSAGETABLE
,
465 if (NT_SUCCESS(Status
))
467 if (MessageResource
->Flags
)
469 RtlInitUnicodeString(&Format2U
, (PWSTR
)MessageResource
->Text
);
470 Format2A
.Buffer
= NULL
;
474 RtlInitAnsiString(&Format2A
, (PCHAR
)MessageResource
->Text
);
475 /* Status = */ RtlAnsiStringToUnicodeString(&Format2U
, &Format2A
, TRUE
);
478 /* Handle special cases */
479 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
)
481 FormatString
= Format2U
.Buffer
;
482 CapturedParameters
[0] = CapturedParameters
[1];
483 CapturedParameters
[1] = CapturedParameters
[3];
484 if (CapturedParameters
[2])
485 CapturedParameters
[2] = (ULONG_PTR
)L
"written";
487 CapturedParameters
[2] = (ULONG_PTR
)L
"read";
489 else if (ExceptionCode
== STATUS_IN_PAGE_ERROR
)
491 FormatString
= Format2U
.Buffer
;
492 CapturedParameters
[0] = CapturedParameters
[1];
493 CapturedParameters
[1] = CapturedParameters
[3];
497 /* Keep the existing FormatString */
498 CapturedParameters
[2] = CapturedParameters
[1];
499 CapturedParameters
[1] = CapturedParameters
[0];
501 pszBuffer
= Format2U
.Buffer
;
502 if (!_wcsnicmp(pszBuffer
, L
"{EXCEPTION}", 11))
505 * This is a named exception. Skip the mark and
506 * retrieve the exception name that follows it.
510 /* Skip '\r', '\n' */
513 CapturedParameters
[0] = (ULONG_PTR
)pszBuffer
;
517 /* Fall back to hardcoded value */
518 CapturedParameters
[0] = (ULONG_PTR
)L
"unknown software exception";
524 /* Fall back to hardcoded value, and keep the existing FormatString */
525 CapturedParameters
[2] = CapturedParameters
[1];
526 CapturedParameters
[1] = CapturedParameters
[0];
527 CapturedParameters
[0] = (ULONG_PTR
)L
"unknown software exception";
530 if (Message
->ValidResponseOptions
== OptionOk
||
531 Message
->ValidResponseOptions
== OptionOkCancel
)
533 /* Reserve space for one newline and the OK-terminate-program string */
534 Size
+= 1 + (g_OKTerminateU
.Length
/ sizeof(WCHAR
));
536 if (Message
->ValidResponseOptions
== OptionOkCancel
)
538 /* Reserve space for one newline and the CANCEL-debug-program string */
539 Size
+= 1 + (g_CancelDebugU
.Length
/ sizeof(WCHAR
));
543 /* Calculate length of text buffer */
544 TextStringU
->MaximumLength
= FormatU
.Length
+ SizeOfStrings
+
545 (USHORT
)(Size
* sizeof(WCHAR
)) +
546 sizeof(UNICODE_NULL
);
548 /* Allocate a buffer for the text */
549 TextStringU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
551 TextStringU
->MaximumLength
);
552 if (!TextStringU
->Buffer
)
554 DPRINT1("Cannot allocate memory for TextStringU\n");
555 Status
= STATUS_NO_MEMORY
;
558 Status
= STATUS_SUCCESS
;
560 /* Wrap in SEH to protect from invalid string parameters */
563 /* Print the string into the buffer */
564 pszBuffer
= TextStringU
->Buffer
;
565 cchBuffer
= TextStringU
->MaximumLength
;
566 RtlStringCbPrintfExW(pszBuffer
, cchBuffer
,
567 &pszBuffer
, &cchBuffer
,
568 STRSAFE_IGNORE_NULLS
,
570 CapturedParameters
[0],
571 CapturedParameters
[1],
572 CapturedParameters
[2],
573 CapturedParameters
[3]);
575 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
577 if (Message
->ValidResponseOptions
== OptionOk
||
578 Message
->ValidResponseOptions
== OptionOkCancel
)
580 RtlStringCbPrintfExW(pszBuffer
, cchBuffer
,
581 &pszBuffer
, &cchBuffer
,
582 STRSAFE_IGNORE_NULLS
,
586 if (Message
->ValidResponseOptions
== OptionOkCancel
)
588 RtlStringCbPrintfExW(pszBuffer
, cchBuffer
,
589 &pszBuffer
, &cchBuffer
,
590 STRSAFE_IGNORE_NULLS
,
596 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
598 /* An exception occurred, use a default string */
599 DPRINT1("Exception 0x%08lx occurred while building hard-error message, fall back to default message.\n",
600 _SEH2_GetExceptionCode());
602 RtlStringCbPrintfW(TextStringU
->Buffer
,
603 TextStringU
->MaximumLength
,
604 L
"Exception processing message 0x%08lx\n"
605 L
"Parameters: 0x%p 0x%p 0x%p 0x%p",
607 CapturedParameters
[0], CapturedParameters
[1],
608 CapturedParameters
[2], CapturedParameters
[3]);
610 /* Set error and free buffers */
611 // Status = _SEH2_GetExceptionCode();
615 if (NT_SUCCESS(Status
))
617 TextStringU
->Length
= wcslen(TextStringU
->Buffer
) * sizeof(WCHAR
);
620 /* Free converted Unicode strings */
621 if (Format2A
.Buffer
) RtlFreeUnicodeString(&Format2U
);
622 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
631 IN ULONG DefaultValue
)
634 ULONG Value
= DefaultValue
;
635 UNICODE_STRING String
;
636 OBJECT_ATTRIBUTES ObjectAttributes
;
639 UCHAR ValueBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
640 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
642 RtlInitUnicodeString(&String
, KeyName
);
643 InitializeObjectAttributes(&ObjectAttributes
,
645 OBJ_CASE_INSENSITIVE
,
649 /* Open the registry key */
650 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
651 if (NT_SUCCESS(Status
))
653 /* Query the value */
654 RtlInitUnicodeString(&String
, ValueName
);
655 Status
= NtQueryValueKey(KeyHandle
,
657 KeyValuePartialInformation
,
662 /* Close the registry key */
665 if (NT_SUCCESS(Status
) && (ValueInfo
->Type
== REG_DWORD
))
667 /* Directly retrieve the data */
668 Value
= *(PULONG
)ValueInfo
->Data
;
676 UserpShowInformationBalloon(PWSTR Text
,
678 PHARDERROR_MSG Message
)
680 ULONG ShellErrorMode
;
682 COPYDATASTRUCT CopyData
;
683 PBALLOON_HARD_ERROR_DATA pdata
;
684 DWORD dwSize
, cbTextLen
, cbTitleLen
;
685 PWCHAR pText
, pCaption
;
688 /* Query the shell error mode value */
689 ShellErrorMode
= GetRegInt(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
690 L
"ShellErrorMode", 0);
692 /* Make the shell display the hard error message in balloon only if necessary */
693 if (ShellErrorMode
!= 1)
696 hwnd
= GetTaskmanWindow();
699 DPRINT1("Failed to find shell task window (last error %lu)\n", GetLastError());
703 cbTextLen
= ((Text
? wcslen(Text
) : 0) + 1) * sizeof(WCHAR
);
704 cbTitleLen
= ((Caption
? wcslen(Caption
) : 0) + 1) * sizeof(WCHAR
);
706 dwSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
707 dwSize
+= cbTextLen
+ cbTitleLen
;
709 pdata
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
712 DPRINT1("Failed to allocate balloon data\n");
716 pdata
->cbHeaderSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
717 pdata
->Status
= Message
->Status
;
719 if (NT_SUCCESS(Message
->Status
))
720 pdata
->dwType
= MB_OK
;
721 else if (Message
->Status
== STATUS_SERVICE_NOTIFICATION
)
722 pdata
->dwType
= Message
->Parameters
[2];
724 pdata
->dwType
= MB_ICONINFORMATION
;
726 pdata
->TitleOffset
= pdata
->cbHeaderSize
;
727 pdata
->MessageOffset
= pdata
->TitleOffset
;
728 pdata
->MessageOffset
+= cbTitleLen
;
729 pCaption
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->TitleOffset
);
730 pText
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->MessageOffset
);
731 wcscpy(pCaption
, Caption
);
734 CopyData
.dwData
= RegisterWindowMessageW(L
"HardError");
735 CopyData
.cbData
= dwSize
;
736 CopyData
.lpData
= pdata
;
740 ret
= SendMessageTimeoutW(hwnd
, WM_COPYDATA
, 0, (LPARAM
)&CopyData
,
741 SMTO_NORMAL
| SMTO_ABORTIFHUNG
, 3000, &dwResult
);
743 RtlFreeHeap(RtlGetProcessHeap(), 0, pdata
);
745 return (ret
&& dwResult
) ? TRUE
: FALSE
;
753 IN ULONG ValidResponseOptions
,
757 ULONG Type
, MessageBoxResponse
;
759 /* Set the message box type */
760 switch (ValidResponseOptions
)
762 case OptionAbortRetryIgnore
:
763 Type
= MB_ABORTRETRYIGNORE
;
771 case OptionRetryCancel
:
772 Type
= MB_RETRYCANCEL
;
777 case OptionYesNoCancel
:
778 Type
= MB_YESNOCANCEL
;
780 case OptionShutdownSystem
:
781 Type
= MB_RETRYCANCEL
; // FIXME???
785 * At that point showing the balloon failed. Is that correct?
787 Type
= MB_OK
; // FIXME!
789 case OptionCancelTryContinue
:
790 Type
= MB_CANCELTRYCONTINUE
;
793 /* Anything else is invalid */
796 DPRINT1("Unknown ValidResponseOptions = %d\n", ValidResponseOptions
);
797 return ResponseNotHandled
;
802 // STATUS_SEVERITY_SUCCESS
803 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
804 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
805 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
807 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
809 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
810 Text
, Caption
, Severity
, Type
);
812 /* Display a message box */
813 MessageBoxResponse
= MessageBoxTimeoutW(NULL
, Text
, Caption
, Type
, 0, Timeout
);
815 /* Return response value */
816 switch (MessageBoxResponse
)
818 case IDOK
: return ResponseOk
;
819 case IDCANCEL
: return ResponseCancel
;
820 case IDYES
: return ResponseYes
;
821 case IDNO
: return ResponseNo
;
822 case IDABORT
: return ResponseAbort
;
823 case IDIGNORE
: return ResponseIgnore
;
824 case IDRETRY
: return ResponseRetry
;
825 case IDTRYAGAIN
: return ResponseTryAgain
;
826 case IDCONTINUE
: return ResponseContinue
;
829 return ResponseNotHandled
;
835 IN PUNICODE_STRING TextStringU
,
836 IN PUNICODE_STRING CaptionStringU
)
840 UNICODE_STRING UNCServerNameU
= {0, 0, NULL
};
841 UNICODE_STRING SourceNameU
= RTL_CONSTANT_STRING(L
"Application Popup");
842 PUNICODE_STRING Strings
[] = {CaptionStringU
, TextStringU
};
844 Status
= ElfRegisterEventSourceW(&UNCServerNameU
, &SourceNameU
, &hEventLog
);
845 if (!NT_SUCCESS(Status
) || !hEventLog
)
847 DPRINT1("ElfRegisterEventSourceW failed with Status 0x%08lx\n", Status
);
851 Status
= ElfReportEventW(hEventLog
,
852 EVENTLOG_INFORMATION_TYPE
,
854 STATUS_LOG_HARD_ERROR
,
863 if (!NT_SUCCESS(Status
))
864 DPRINT1("ElfReportEventW failed with Status 0x%08lx\n", Status
);
866 ElfDeregisterEventSource(hEventLog
);
872 IN PCSR_THREAD ThreadData
,
873 IN PHARDERROR_MSG Message
)
875 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
] = {0};
876 OBJECT_ATTRIBUTES ObjectAttributes
;
877 UNICODE_STRING TextU
, CaptionU
;
883 ASSERT(ThreadData
->Process
!= NULL
);
885 /* Default to not handled */
886 Message
->Response
= ResponseNotHandled
;
888 /* Make sure we don't have too many parameters */
889 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
891 // FIXME: Windows just fails (STATUS_INVALID_PARAMETER) & returns ResponseNotHandled.
892 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
894 if (Message
->ValidResponseOptions
> OptionCancelTryContinue
)
896 // STATUS_INVALID_PARAMETER;
897 Message
->Response
= ResponseNotHandled
;
900 // TODO: More message validation: check NumberOfParameters wrt. Message Status code.
902 /* Open client process */
903 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
904 Status
= NtOpenProcess(&hProcess
,
905 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
907 &Message
->h
.ClientId
);
908 if (!NT_SUCCESS(Status
))
910 DPRINT1("NtOpenProcess failed with status 0x%08lx, possibly SYSTEM process.\n", Status
);
914 /* Re-initialize the hard errors cache */
915 UserInitHardErrorsCache();
917 /* Capture all string parameters from the process memory */
918 UserpCaptureStringParameters(Parameters
, &Size
, Message
, hProcess
);
920 /* Format the message caption and text */
921 Status
= UserpFormatMessages(&TextU
,
929 UserpFreeStringParameters(Parameters
, Message
);
930 if (hProcess
) NtClose(hProcess
);
932 /* If we failed, bail out */
933 if (!NT_SUCCESS(Status
))
936 /* Log the hard error message */
937 UserpLogHardError(&TextU
, &CaptionU
);
939 /* Display a hard error popup depending on the current ErrorMode */
941 /* Query the error mode value */
942 ErrorMode
= GetRegInt(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
945 if (Message
->Status
!= STATUS_SERVICE_NOTIFICATION
&& ErrorMode
!= 0)
947 /* Returns OK for the hard error */
948 Message
->Response
= ResponseOk
;
952 if (Message
->ValidResponseOptions
== OptionOkNoWait
)
954 /* Display the balloon */
955 Message
->Response
= ResponseOk
;
956 if (UserpShowInformationBalloon(TextU
.Buffer
,
960 Message
->Response
= ResponseOk
;
965 /* Display the message box */
966 Message
->Response
= UserpMessageBox(TextU
.Buffer
,
968 Message
->ValidResponseOptions
,
969 (ULONG
)(Message
->Status
) >> 30,
973 RtlFreeUnicodeString(&TextU
);
974 RtlFreeUnicodeString(&CaptionU
);
980 UserInitHardErrorsCache(VOID
)
983 LCID CurrentUserLCID
= 0;
985 Status
= NtQueryDefaultLocale(TRUE
, &CurrentUserLCID
);
986 if (!NT_SUCCESS(Status
) || CurrentUserLCID
== 0)
988 /* Fall back to english locale */
989 DPRINT1("NtQueryDefaultLocale failed with Status = 0x%08lx\n", Status
);
990 // LOCALE_SYSTEM_DEFAULT;
991 CurrentUserLCID
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
993 if (g_CurrentUserLangId
== LANGIDFROMLCID(CurrentUserLCID
))
995 /* The current lang ID and the hard error strings have already been cached */
999 /* Load the strings using the current system locale */
1000 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_SUCCESS
,
1001 &g_SuccessU
, L
"Success");
1002 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_INFORMATIONAL
,
1003 &g_InformationU
, L
"System Information");
1004 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_WARNING
,
1005 &g_WarningU
, L
"System Warning");
1006 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_ERROR
,
1007 &g_ErrorU
, L
"System Error");
1008 // "unknown software exception"
1009 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SYSTEM_PROCESS
,
1010 &g_SystemProcessU
, L
"System Process");
1011 RtlLoadUnicodeString(UserServerDllInstance
, IDS_OK_TERMINATE_PROGRAM
,
1012 &g_OKTerminateU
, L
"Click on OK to terminate the program.");
1013 RtlLoadUnicodeString(UserServerDllInstance
, IDS_CANCEL_DEBUG_PROGRAM
,
1014 &g_CancelDebugU
, L
"Click on CANCEL to debug the program.");
1016 /* Remember that we cached the hard error strings */
1017 g_CurrentUserLangId
= LANGIDFROMLCID(CurrentUserLCID
);