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 UserpCaptureStringParameters(
79 OUT PULONG_PTR Parameters
,
80 OUT PULONG SizeOfAllUnicodeStrings
,
81 IN PHARDERROR_MSG Message
,
82 IN HANDLE hProcess OPTIONAL
)
85 ULONG nParam
, Size
= 0;
86 UNICODE_STRING TempStringU
, ParamStringU
;
87 ANSI_STRING TempStringA
;
89 if (SizeOfAllUnicodeStrings
)
90 *SizeOfAllUnicodeStrings
= 0;
92 /* Read all strings from client space */
93 for (nParam
= 0; nParam
< Message
->NumberOfParameters
; ++nParam
)
95 Parameters
[nParam
] = 0;
97 /* Check if the current parameter is a unicode string */
98 if (Message
->UnicodeStringParameterMask
& (1 << nParam
))
100 /* Skip this string if we do not have a client process */
104 /* Read the UNICODE_STRING from the process memory */
105 Status
= NtReadVirtualMemory(hProcess
,
106 (PVOID
)Message
->Parameters
[nParam
],
108 sizeof(ParamStringU
),
110 if (!NT_SUCCESS(Status
))
112 /* We failed, skip this string */
113 DPRINT1("NtReadVirtualMemory(Message->Parameters) failed, Status 0x%lx, skipping.\n", Status
);
117 /* Allocate a buffer for the string */
118 TempStringU
.MaximumLength
= ParamStringU
.Length
;
119 TempStringU
.Length
= ParamStringU
.Length
;
120 TempStringU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
122 TempStringU
.MaximumLength
);
123 if (!TempStringU
.Buffer
)
125 /* We failed, skip this string */
126 DPRINT1("Cannot allocate memory with size %u, skipping.\n", TempStringU
.MaximumLength
);
130 /* Read the string buffer from the process memory */
131 Status
= NtReadVirtualMemory(hProcess
,
136 if (!NT_SUCCESS(Status
))
138 /* We failed, skip this string */
139 DPRINT1("NtReadVirtualMemory(ParamStringU) failed, Status 0x%lx, skipping.\n", Status
);
140 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
144 DPRINT("ParamString = \'%wZ\'\n", &TempStringU
);
146 /* Allocate a buffer for converted to ANSI string */
147 TempStringA
.MaximumLength
= RtlUnicodeStringToAnsiSize(&TempStringU
);
148 TempStringA
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
150 TempStringA
.MaximumLength
);
151 if (!TempStringA
.Buffer
)
153 /* We failed, skip this string */
154 DPRINT1("Cannot allocate memory with size %u, skipping.\n", TempStringA
.MaximumLength
);
155 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
159 /* Convert string to ANSI and free temporary buffer */
160 Status
= RtlUnicodeStringToAnsiString(&TempStringA
, &TempStringU
, FALSE
);
161 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringU
.Buffer
);
162 if (!NT_SUCCESS(Status
))
164 /* We failed, skip this string */
165 DPRINT1("RtlUnicodeStringToAnsiString() failed, Status 0x%lx, skipping.\n", Status
);
166 RtlFreeHeap(RtlGetProcessHeap(), 0, TempStringA
.Buffer
);
170 /* Note: RtlUnicodeStringToAnsiString returns NULL terminated string */
171 Parameters
[nParam
] = (ULONG_PTR
)TempStringA
.Buffer
;
172 Size
+= TempStringU
.Length
;
176 /* It's not a unicode string, just copy the parameter */
177 Parameters
[nParam
] = Message
->Parameters
[nParam
];
181 if (SizeOfAllUnicodeStrings
)
182 *SizeOfAllUnicodeStrings
= Size
;
187 UserpFreeStringParameters(
188 IN OUT PULONG_PTR Parameters
,
189 IN PHARDERROR_MSG Message
)
193 /* Loop all parameters */
194 for (nParam
= 0; nParam
< Message
->NumberOfParameters
; ++nParam
)
196 /* Check if the current parameter is a string */
197 if ((Message
->UnicodeStringParameterMask
& (1 << nParam
)) && (Parameters
[nParam
] != 0))
199 /* Free the string buffer */
200 RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID
)Parameters
[nParam
]);
207 UserpGetClientFileName(
208 OUT PUNICODE_STRING ClientFileNameU
,
211 PLIST_ENTRY ModuleListHead
;
213 PLDR_DATA_TABLE_ENTRY Module
;
215 PROCESS_BASIC_INFORMATION ClientBasicInfo
;
216 LDR_DATA_TABLE_ENTRY ModuleData
;
221 /* Initialize string */
222 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
224 /* Query process information */
225 Status
= NtQueryInformationProcess(hProcess
,
226 ProcessBasicInformation
,
228 sizeof(ClientBasicInfo
),
230 if (!NT_SUCCESS(Status
)) return Status
;
232 /* Locate the process loader data table and retrieve its name from it */
234 Peb
= ClientBasicInfo
.PebBaseAddress
;
235 if (!Peb
) return STATUS_UNSUCCESSFUL
;
237 Status
= NtReadVirtualMemory(hProcess
, &Peb
->Ldr
, &Ldr
, sizeof(Ldr
), NULL
);
238 if (!NT_SUCCESS(Status
)) return Status
;
240 ModuleListHead
= &Ldr
->InLoadOrderModuleList
;
241 Status
= NtReadVirtualMemory(hProcess
,
242 &ModuleListHead
->Flink
,
246 if (!NT_SUCCESS(Status
)) return Status
;
248 if (Entry
== ModuleListHead
) return STATUS_UNSUCCESSFUL
;
250 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
252 Status
= NtReadVirtualMemory(hProcess
,
257 if (!NT_SUCCESS(Status
)) return Status
;
259 Status
= NtReadVirtualMemory(hProcess
,
260 &Peb
->ImageBaseAddress
,
262 sizeof(ClientDllBase
),
264 if (!NT_SUCCESS(Status
)) return Status
;
266 if (ClientDllBase
!= ModuleData
.DllBase
) return STATUS_UNSUCCESSFUL
;
268 ClientFileNameU
->MaximumLength
= ModuleData
.BaseDllName
.MaximumLength
;
269 ClientFileNameU
->Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
271 ClientFileNameU
->MaximumLength
);
272 if (!ClientFileNameU
->Buffer
)
274 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
275 return STATUS_NO_MEMORY
;
278 Status
= NtReadVirtualMemory(hProcess
,
279 ModuleData
.BaseDllName
.Buffer
,
280 ClientFileNameU
->Buffer
,
281 ClientFileNameU
->MaximumLength
,
283 if (!NT_SUCCESS(Status
))
285 RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU
->Buffer
);
286 RtlInitEmptyUnicodeString(ClientFileNameU
, NULL
, 0);
290 ClientFileNameU
->Length
= (USHORT
)(wcslen(ClientFileNameU
->Buffer
) * sizeof(WCHAR
));
291 DPRINT("ClientFileNameU = \'%wZ\'\n", &ClientFileNameU
);
293 return STATUS_SUCCESS
;
299 IN OUT PUNICODE_STRING TextStringU
,
300 IN OUT PUNICODE_STRING CaptionStringU
,
301 IN PHARDERROR_MSG Message
)
304 OBJECT_ATTRIBUTES ObjectAttributes
;
307 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
] = {0};
308 ULONG_PTR CopyParameters
[MAXIMUM_HARDERROR_PARAMETERS
];
309 UNICODE_STRING WindowTitleU
, FileNameU
, TempStringU
, FormatU
, Format2U
;
310 ANSI_STRING FormatA
, Format2A
;
312 PMESSAGE_RESOURCE_ENTRY MessageResource
;
313 PWSTR FormatString
, pszBuffer
;
318 /* Open client process */
319 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
320 Status
= NtOpenProcess(&hProcess
,
321 PROCESS_VM_READ
| PROCESS_QUERY_INFORMATION
,
323 &Message
->h
.ClientId
);
324 if (!NT_SUCCESS(Status
))
326 DPRINT1("NtOpenProcess failed with status 0x%08lx, possibly SYSTEM process.\n", Status
);
330 /* Capture all string parameters from the process memory */
331 UserpCaptureStringParameters(Parameters
, &SizeOfStrings
, Message
, hProcess
);
333 /* Copy the Parameters array locally */
334 RtlCopyMemory(&CopyParameters
, Parameters
, sizeof(CopyParameters
));
336 /* Get the file name of the client process */
337 Status
= STATUS_SUCCESS
;
339 Status
= UserpGetClientFileName(&FileNameU
, hProcess
);
341 /* Close the process handle but keep its original value to know where stuff came from */
342 if (hProcess
) NtClose(hProcess
);
345 * Fall back to SYSTEM process if the client process handle
346 * was NULL or we failed retrieving a file name.
348 if (!hProcess
|| !NT_SUCCESS(Status
) || !FileNameU
.Buffer
)
351 FileNameU
= g_SystemProcessU
;
354 Severity
= (ULONG
)(Message
->Status
) >> 30;
356 /* Get text string of the error code */
357 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
358 (ULONG_PTR
)RT_MESSAGETABLE
,
362 if (NT_SUCCESS(Status
))
364 if (MessageResource
->Flags
)
366 RtlInitUnicodeString(&FormatU
, (PWSTR
)MessageResource
->Text
);
367 FormatA
.Buffer
= NULL
;
371 RtlInitAnsiString(&FormatA
, (PCHAR
)MessageResource
->Text
);
372 /* Status = */ RtlAnsiStringToUnicodeString(&FormatU
, &FormatA
, TRUE
);
377 /* Fall back to hardcoded value */
378 RtlInitUnicodeString(&FormatU
, L
"Unknown Hard Error");
379 FormatA
.Buffer
= NULL
;
382 FormatString
= FormatU
.Buffer
;
384 /* Check whether a caption exists */
385 if (FormatString
[0] == L
'{')
387 /* Set caption start */
388 TempStringU
.Buffer
= ++FormatString
;
390 /* Get size of the caption */
391 for (Size
= 0; *FormatString
!= UNICODE_NULL
&& *FormatString
!= L
'}'; Size
++)
394 /* Skip '}', '\r', '\n' */
397 TempStringU
.Length
= (USHORT
)(Size
* sizeof(WCHAR
));
398 TempStringU
.MaximumLength
= TempStringU
.Length
;
402 if (Severity
== STATUS_SEVERITY_SUCCESS
)
403 TempStringU
= g_SuccessU
;
404 else if (Severity
== STATUS_SEVERITY_INFORMATIONAL
)
405 TempStringU
= g_InformationU
;
406 else if (Severity
== STATUS_SEVERITY_WARNING
)
407 TempStringU
= g_WarningU
;
408 else if (Severity
== STATUS_SEVERITY_ERROR
)
409 TempStringU
= g_ErrorU
;
411 ASSERT(FALSE
); // Unexpected, since Severity is only <= 3.
414 /* Retrieve the window title of the client, if it has one */
415 RtlInitEmptyUnicodeString(&WindowTitleU
, NULL
, 0);
417 EnumThreadWindows(HandleToUlong(Message
->h
.ClientId
.UniqueThread
),
418 FindTopLevelWnd
, (LPARAM
)&hwndOwner
);
421 cszBuffer
= GetWindowTextLengthW(hwndOwner
);
424 cszBuffer
+= 3; // 2 characters for ": " and a NULL terminator.
425 WindowTitleU
.MaximumLength
= (USHORT
)(cszBuffer
* sizeof(WCHAR
));
426 WindowTitleU
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
428 WindowTitleU
.MaximumLength
);
429 if (WindowTitleU
.Buffer
)
431 cszBuffer
= GetWindowTextW(hwndOwner
,
433 WindowTitleU
.MaximumLength
/ sizeof(WCHAR
));
434 WindowTitleU
.Length
= (USHORT
)(cszBuffer
* sizeof(WCHAR
));
435 RtlAppendUnicodeToString(&WindowTitleU
, L
": ");
439 RtlInitEmptyUnicodeString(&WindowTitleU
, NULL
, 0);
444 /* Calculate buffer length for the caption */
445 cszBuffer
= WindowTitleU
.Length
+ FileNameU
.Length
+ TempStringU
.Length
+
446 3 * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
447 if (cszBuffer
> CaptionStringU
->MaximumLength
)
449 /* Allocate a larger buffer for the caption */
450 pszBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
455 /* We could not allocate a larger buffer; continue using the smaller static buffer */
456 DPRINT1("Cannot allocate memory for CaptionStringU, use static buffer.\n");
460 RtlInitEmptyUnicodeString(CaptionStringU
, pszBuffer
, (USHORT
)cszBuffer
);
463 CaptionStringU
->Length
= 0;
465 /* Append the file name, the separator and the caption text */
466 RtlStringCbPrintfW(CaptionStringU
->Buffer
,
467 CaptionStringU
->MaximumLength
,
469 &WindowTitleU
, &FileNameU
, &TempStringU
);
470 CaptionStringU
->Length
= (USHORT
)(wcslen(CaptionStringU
->Buffer
) * sizeof(WCHAR
));
472 /* Free string buffers if needed */
473 if (WindowTitleU
.Buffer
) RtlFreeUnicodeString(&WindowTitleU
);
474 if (hProcess
) RtlFreeUnicodeString(&FileNameU
);
476 // FIXME: What is 42 == ??
479 /* Check if this is an exception message */
480 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
482 ULONG ExceptionCode
= CopyParameters
[0];
484 /* Get text string of the exception code */
485 Status
= RtlFindMessage(GetModuleHandleW(L
"ntdll"),
486 (ULONG_PTR
)RT_MESSAGETABLE
,
490 if (NT_SUCCESS(Status
))
492 if (MessageResource
->Flags
)
494 RtlInitUnicodeString(&Format2U
, (PWSTR
)MessageResource
->Text
);
495 Format2A
.Buffer
= NULL
;
499 RtlInitAnsiString(&Format2A
, (PCHAR
)MessageResource
->Text
);
500 /* Status = */ RtlAnsiStringToUnicodeString(&Format2U
, &Format2A
, TRUE
);
503 /* Handle special cases */
504 if (ExceptionCode
== STATUS_ACCESS_VIOLATION
)
506 FormatString
= Format2U
.Buffer
;
507 CopyParameters
[0] = CopyParameters
[1];
508 CopyParameters
[1] = CopyParameters
[3];
509 if (CopyParameters
[2])
510 CopyParameters
[2] = (ULONG_PTR
)L
"written";
512 CopyParameters
[2] = (ULONG_PTR
)L
"read";
514 else if (ExceptionCode
== STATUS_IN_PAGE_ERROR
)
516 FormatString
= Format2U
.Buffer
;
517 CopyParameters
[0] = CopyParameters
[1];
518 CopyParameters
[1] = CopyParameters
[3];
522 /* Keep the existing FormatString */
523 CopyParameters
[2] = CopyParameters
[1];
524 CopyParameters
[1] = CopyParameters
[0];
526 pszBuffer
= Format2U
.Buffer
;
527 if (!_wcsnicmp(pszBuffer
, L
"{EXCEPTION}", 11))
530 * This is a named exception. Skip the mark and
531 * retrieve the exception name that follows it.
535 /* Skip '\r', '\n' */
538 CopyParameters
[0] = (ULONG_PTR
)pszBuffer
;
542 /* Fall back to hardcoded value */
543 CopyParameters
[0] = (ULONG_PTR
)L
"unknown software exception";
549 /* Fall back to hardcoded value, and keep the existing FormatString */
550 CopyParameters
[2] = CopyParameters
[1];
551 CopyParameters
[1] = CopyParameters
[0];
552 CopyParameters
[0] = (ULONG_PTR
)L
"unknown software exception";
555 if (Message
->ValidResponseOptions
== OptionOk
||
556 Message
->ValidResponseOptions
== OptionOkCancel
)
558 /* Reserve space for one newline and the OK-terminate-program string */
559 Size
+= 1 + (g_OKTerminateU
.Length
/ sizeof(WCHAR
));
561 if (Message
->ValidResponseOptions
== OptionOkCancel
)
563 /* Reserve space for one newline and the CANCEL-debug-program string */
564 Size
+= 1 + (g_CancelDebugU
.Length
/ sizeof(WCHAR
));
568 /* Calculate buffer length for the text message */
569 cszBuffer
= FormatU
.Length
+ SizeOfStrings
+ Size
* sizeof(WCHAR
) +
570 sizeof(UNICODE_NULL
);
571 if (cszBuffer
> TextStringU
->MaximumLength
)
573 /* Allocate a larger buffer for the text message */
574 pszBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
579 /* We could not allocate a larger buffer; continue using the smaller static buffer */
580 DPRINT1("Cannot allocate memory for TextStringU, use static buffer.\n");
584 RtlInitEmptyUnicodeString(TextStringU
, pszBuffer
, (USHORT
)cszBuffer
);
587 TextStringU
->Length
= 0;
589 /* Wrap in SEH to protect from invalid string parameters */
592 /* Print the string into the buffer */
593 pszBuffer
= TextStringU
->Buffer
;
594 cszBuffer
= TextStringU
->MaximumLength
;
595 RtlStringCbPrintfExW(pszBuffer
, cszBuffer
,
596 &pszBuffer
, &cszBuffer
,
597 STRSAFE_IGNORE_NULLS
,
599 CopyParameters
[0], CopyParameters
[1],
600 CopyParameters
[2], CopyParameters
[3]);
602 if (Message
->Status
== STATUS_UNHANDLED_EXCEPTION
)
604 if (Message
->ValidResponseOptions
== OptionOk
||
605 Message
->ValidResponseOptions
== OptionOkCancel
)
607 RtlStringCbPrintfExW(pszBuffer
, cszBuffer
,
608 &pszBuffer
, &cszBuffer
,
609 STRSAFE_IGNORE_NULLS
,
613 if (Message
->ValidResponseOptions
== OptionOkCancel
)
615 RtlStringCbPrintfExW(pszBuffer
, cszBuffer
,
616 &pszBuffer
, &cszBuffer
,
617 STRSAFE_IGNORE_NULLS
,
623 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
625 /* An exception occurred, use a default string with the original parameters */
626 DPRINT1("Exception 0x%08lx occurred while building hard-error message, fall back to default message.\n",
627 _SEH2_GetExceptionCode());
629 RtlStringCbPrintfW(TextStringU
->Buffer
,
630 TextStringU
->MaximumLength
,
631 L
"Exception processing message 0x%08lx\n"
632 L
"Parameters: 0x%p 0x%p 0x%p 0x%p",
634 Parameters
[0], Parameters
[1],
635 Parameters
[2], Parameters
[3]);
639 TextStringU
->Length
= (USHORT
)(wcslen(TextStringU
->Buffer
) * sizeof(WCHAR
));
641 /* Free converted Unicode strings */
642 if (Format2A
.Buffer
) RtlFreeUnicodeString(&Format2U
);
643 if (FormatA
.Buffer
) RtlFreeUnicodeString(&FormatU
);
646 UserpFreeStringParameters(Parameters
, Message
);
653 IN ULONG DefaultValue
)
656 ULONG Value
= DefaultValue
;
657 UNICODE_STRING String
;
658 OBJECT_ATTRIBUTES ObjectAttributes
;
661 UCHAR ValueBuffer
[sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(ULONG
)];
662 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
664 RtlInitUnicodeString(&String
, KeyName
);
665 InitializeObjectAttributes(&ObjectAttributes
,
667 OBJ_CASE_INSENSITIVE
,
671 /* Open the registry key */
672 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
673 if (NT_SUCCESS(Status
))
675 /* Query the value */
676 RtlInitUnicodeString(&String
, ValueName
);
677 Status
= NtQueryValueKey(KeyHandle
,
679 KeyValuePartialInformation
,
684 /* Close the registry key */
687 if (NT_SUCCESS(Status
) && (ValueInfo
->Type
== REG_DWORD
))
689 /* Directly retrieve the data */
690 Value
= *(PULONG
)ValueInfo
->Data
;
698 UserpShowInformationBalloon(PWSTR Text
,
700 PHARDERROR_MSG Message
)
702 ULONG ShellErrorMode
;
704 COPYDATASTRUCT CopyData
;
705 PBALLOON_HARD_ERROR_DATA pdata
;
706 DWORD dwSize
, cbTextLen
, cbTitleLen
;
707 PWCHAR pText
, pCaption
;
710 /* Query the shell error mode value */
711 ShellErrorMode
= GetRegInt(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
712 L
"ShellErrorMode", 0);
714 /* Make the shell display the hard error message in balloon only if necessary */
715 if (ShellErrorMode
!= 1)
718 hwnd
= GetTaskmanWindow();
721 DPRINT1("Failed to find shell task window (last error %lu)\n", GetLastError());
725 cbTextLen
= ((Text
? wcslen(Text
) : 0) + 1) * sizeof(WCHAR
);
726 cbTitleLen
= ((Caption
? wcslen(Caption
) : 0) + 1) * sizeof(WCHAR
);
728 dwSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
729 dwSize
+= cbTextLen
+ cbTitleLen
;
731 pdata
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
734 DPRINT1("Failed to allocate balloon data\n");
738 pdata
->cbHeaderSize
= sizeof(BALLOON_HARD_ERROR_DATA
);
739 pdata
->Status
= Message
->Status
;
741 if (NT_SUCCESS(Message
->Status
))
742 pdata
->dwType
= MB_OK
;
743 else if (Message
->Status
== STATUS_SERVICE_NOTIFICATION
)
744 pdata
->dwType
= Message
->Parameters
[2];
746 pdata
->dwType
= MB_ICONINFORMATION
;
748 pdata
->TitleOffset
= pdata
->cbHeaderSize
;
749 pdata
->MessageOffset
= pdata
->TitleOffset
;
750 pdata
->MessageOffset
+= cbTitleLen
;
751 pCaption
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->TitleOffset
);
752 pText
= (PWCHAR
)((ULONG_PTR
)pdata
+ pdata
->MessageOffset
);
753 wcscpy(pCaption
, Caption
);
756 CopyData
.dwData
= RegisterWindowMessageW(L
"HardError");
757 CopyData
.cbData
= dwSize
;
758 CopyData
.lpData
= pdata
;
762 ret
= SendMessageTimeoutW(hwnd
, WM_COPYDATA
, 0, (LPARAM
)&CopyData
,
763 SMTO_NORMAL
| SMTO_ABORTIFHUNG
, 3000, &dwResult
);
765 RtlFreeHeap(RtlGetProcessHeap(), 0, pdata
);
767 return (ret
&& dwResult
) ? TRUE
: FALSE
;
775 IN ULONG ValidResponseOptions
,
779 ULONG Type
, MessageBoxResponse
;
781 /* Set the message box type */
782 switch (ValidResponseOptions
)
784 case OptionAbortRetryIgnore
:
785 Type
= MB_ABORTRETRYIGNORE
;
793 case OptionRetryCancel
:
794 Type
= MB_RETRYCANCEL
;
799 case OptionYesNoCancel
:
800 Type
= MB_YESNOCANCEL
;
802 case OptionShutdownSystem
:
803 Type
= MB_RETRYCANCEL
; // FIXME???
807 * At that point showing the balloon failed. Is that correct?
809 Type
= MB_OK
; // FIXME!
811 case OptionCancelTryContinue
:
812 Type
= MB_CANCELTRYCONTINUE
;
815 /* Anything else is invalid */
818 DPRINT1("Unknown ValidResponseOptions = %d\n", ValidResponseOptions
);
819 return ResponseNotHandled
;
824 // STATUS_SEVERITY_SUCCESS
825 if (Severity
== STATUS_SEVERITY_INFORMATIONAL
) Type
|= MB_ICONINFORMATION
;
826 else if (Severity
== STATUS_SEVERITY_WARNING
) Type
|= MB_ICONWARNING
;
827 else if (Severity
== STATUS_SEVERITY_ERROR
) Type
|= MB_ICONERROR
;
829 Type
|= MB_SYSTEMMODAL
| MB_SETFOREGROUND
;
831 DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n",
832 Text
, Caption
, Severity
, Type
);
834 /* Display a message box */
835 MessageBoxResponse
= MessageBoxTimeoutW(NULL
, Text
, Caption
, Type
, 0, Timeout
);
837 /* Return response value */
838 switch (MessageBoxResponse
)
840 case IDOK
: return ResponseOk
;
841 case IDCANCEL
: return ResponseCancel
;
842 case IDYES
: return ResponseYes
;
843 case IDNO
: return ResponseNo
;
844 case IDABORT
: return ResponseAbort
;
845 case IDIGNORE
: return ResponseIgnore
;
846 case IDRETRY
: return ResponseRetry
;
847 case IDTRYAGAIN
: return ResponseTryAgain
;
848 case IDCONTINUE
: return ResponseContinue
;
851 return ResponseNotHandled
;
857 IN PUNICODE_STRING TextStringU
,
858 IN PUNICODE_STRING CaptionStringU
)
862 UNICODE_STRING UNCServerNameU
= {0, 0, NULL
};
863 UNICODE_STRING SourceNameU
= RTL_CONSTANT_STRING(L
"Application Popup");
864 PUNICODE_STRING Strings
[] = {CaptionStringU
, TextStringU
};
866 Status
= ElfRegisterEventSourceW(&UNCServerNameU
, &SourceNameU
, &hEventLog
);
867 if (!NT_SUCCESS(Status
) || !hEventLog
)
869 DPRINT1("ElfRegisterEventSourceW failed with Status 0x%08lx\n", Status
);
873 Status
= ElfReportEventW(hEventLog
,
874 EVENTLOG_INFORMATION_TYPE
,
876 STATUS_LOG_HARD_ERROR
,
885 if (!NT_SUCCESS(Status
))
886 DPRINT1("ElfReportEventW failed with Status 0x%08lx\n", Status
);
888 ElfDeregisterEventSource(hEventLog
);
894 IN PCSR_THREAD ThreadData
,
895 IN PHARDERROR_MSG Message
)
898 UNICODE_STRING TextU
, CaptionU
;
899 WCHAR LocalTextBuffer
[256];
900 WCHAR LocalCaptionBuffer
[256];
902 ASSERT(ThreadData
->Process
!= NULL
);
904 /* Default to not handled */
905 Message
->Response
= ResponseNotHandled
;
907 /* Make sure we don't have too many parameters */
908 if (Message
->NumberOfParameters
> MAXIMUM_HARDERROR_PARAMETERS
)
910 // FIXME: Windows just fails (STATUS_INVALID_PARAMETER) & returns ResponseNotHandled.
911 Message
->NumberOfParameters
= MAXIMUM_HARDERROR_PARAMETERS
;
913 if (Message
->ValidResponseOptions
> OptionCancelTryContinue
)
915 // STATUS_INVALID_PARAMETER;
916 Message
->Response
= ResponseNotHandled
;
919 // TODO: More message validation: check NumberOfParameters wrt. Message Status code.
921 /* Re-initialize the hard errors cache */
922 UserInitHardErrorsCache();
924 /* Format the message caption and text */
925 RtlInitEmptyUnicodeString(&TextU
, LocalTextBuffer
, sizeof(LocalTextBuffer
));
926 RtlInitEmptyUnicodeString(&CaptionU
, LocalCaptionBuffer
, sizeof(LocalCaptionBuffer
));
927 UserpFormatMessages(&TextU
, &CaptionU
, Message
);
929 /* Log the hard error message */
930 UserpLogHardError(&TextU
, &CaptionU
);
932 /* Display a hard error popup depending on the current ErrorMode */
934 /* Query the error mode value */
935 ErrorMode
= GetRegInt(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
938 if (Message
->Status
!= STATUS_SERVICE_NOTIFICATION
&& ErrorMode
!= 0)
940 /* Returns OK for the hard error */
941 Message
->Response
= ResponseOk
;
945 if (Message
->ValidResponseOptions
== OptionOkNoWait
)
947 /* Display the balloon */
948 Message
->Response
= ResponseOk
;
949 if (UserpShowInformationBalloon(TextU
.Buffer
,
953 Message
->Response
= ResponseOk
;
958 /* Display the message box */
959 Message
->Response
= UserpMessageBox(TextU
.Buffer
,
961 Message
->ValidResponseOptions
,
962 (ULONG
)(Message
->Status
) >> 30,
966 /* Free the strings if they have been reallocated */
967 if (TextU
.Buffer
!= LocalTextBuffer
)
968 RtlFreeUnicodeString(&TextU
);
969 if (CaptionU
.Buffer
!= LocalCaptionBuffer
)
970 RtlFreeUnicodeString(&CaptionU
);
976 UserInitHardErrorsCache(VOID
)
979 LCID CurrentUserLCID
= 0;
981 Status
= NtQueryDefaultLocale(TRUE
, &CurrentUserLCID
);
982 if (!NT_SUCCESS(Status
) || CurrentUserLCID
== 0)
984 /* Fall back to english locale */
985 DPRINT1("NtQueryDefaultLocale failed with Status = 0x%08lx\n", Status
);
986 // LOCALE_SYSTEM_DEFAULT;
987 CurrentUserLCID
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
989 if (g_CurrentUserLangId
== LANGIDFROMLCID(CurrentUserLCID
))
991 /* The current lang ID and the hard error strings have already been cached */
995 /* Load the strings using the current system locale */
996 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_SUCCESS
,
997 &g_SuccessU
, L
"Success");
998 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_INFORMATIONAL
,
999 &g_InformationU
, L
"System Information");
1000 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_WARNING
,
1001 &g_WarningU
, L
"System Warning");
1002 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SEVERITY_ERROR
,
1003 &g_ErrorU
, L
"System Error");
1004 // "unknown software exception"
1005 RtlLoadUnicodeString(UserServerDllInstance
, IDS_SYSTEM_PROCESS
,
1006 &g_SystemProcessU
, L
"System Process");
1007 RtlLoadUnicodeString(UserServerDllInstance
, IDS_OK_TERMINATE_PROGRAM
,
1008 &g_OKTerminateU
, L
"Click on OK to terminate the program.");
1009 RtlLoadUnicodeString(UserServerDllInstance
, IDS_CANCEL_DEBUG_PROGRAM
,
1010 &g_CancelDebugU
, L
"Click on CANCEL to debug the program.");
1012 /* Remember that we cached the hard error strings */
1013 g_CurrentUserLangId
= LANGIDFROMLCID(CurrentUserLCID
);