1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/app/hard_error_handler_win.h"
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/string_piece.h"
14 #include "base/sys_string_conversions.h"
18 const int32 kExceptionModuleNotFound
= VcppException(ERROR_SEVERITY_ERROR
,
20 const int32 kExceptionEntryPtNotFound
= VcppException(ERROR_SEVERITY_ERROR
,
21 ERROR_PROC_NOT_FOUND
);
23 const int32 NT_STATUS_ENTRYPOINT_NOT_FOUND
= 0xC0000139;
24 const int32 NT_STATUS_DLL_NOT_FOUND
= 0xC0000135;
26 bool MakeNTUnicodeString(const std::wstring
& str
,
27 UNICODE_STRING
* nt_string
) {
30 size_t str_size_bytes
= str
.size() * sizeof(wchar_t);
31 if (kuint16max
< str_size_bytes
) {
32 // The string is too long - nt_string->Length is USHORT
33 NOTREACHED() << "The string is too long";
36 nt_string
->Length
= static_cast<USHORT
>(str_size_bytes
);
37 nt_string
->MaximumLength
= static_cast<USHORT
>(str_size_bytes
);
38 nt_string
->Buffer
= const_cast<wchar_t*>(str
.c_str());
42 // NT-level function (not a win32 api) used to tell CSRSS of a critical error
43 // in the program which results in a message box dialog.
44 // The |exception| parameter is a standard exception code, the |param_count|
45 // indicates the number of items in |payload_params|. |payload_params| is
46 // dependent on the |exception| type but is typically an array to pointers to
47 // strings. |error_mode| indicates the kind of dialog buttons to show.
48 typedef LONG (WINAPI
*NtRaiseHardErrorPF
)(LONG exception
,
55 // Helper function to call NtRaiseHardError(). It takes the exception code
56 // and one or two strings which are dependent on the exception code. No
57 // effort is done to validate that they match.
58 void RaiseHardErrorMsg(int32 exception
, const std::wstring
& text1
,
59 const std::wstring
& text2
) {
60 // Bind the entry point. We can do it here since this function is really
61 // called at most once per session. Usually never called.
62 NtRaiseHardErrorPF NtRaiseHardError
=
63 reinterpret_cast<NtRaiseHardErrorPF
>(
64 ::GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtRaiseHardError"));
65 if (!NtRaiseHardError
)
68 UNICODE_STRING uni_str1
;
69 UNICODE_STRING uni_str2
;
70 // A message needs to be displayed or else it would be confusing to the user.
71 if (!MakeNTUnicodeString(text1
, &uni_str1
))
74 // The second string is optional.
75 if (MakeNTUnicodeString(text2
, &uni_str2
))
78 UNICODE_STRING
* args
[] = {&uni_str1
, &uni_str2
};
79 uint32 undoc_value
= 3; // Display message to user.
80 uint32 error_mode
= 1; // Display OK button only.
81 ULONG response
; // What user clicked in the dialog. Discarded.
82 NtRaiseHardError(exception
, num_params
, 3, args
, error_mode
, &response
);
87 // Using RaiseHardErrorMsg(), it generates the same message box that is seen
88 // when the loader cannot find a DLL that a module depends on. |module| is the
89 // DLL name and it cannot be empty. The Message box only has an 'ok' button.
90 void ModuleNotFoundHardError(const char* module
) {
93 std::wstring
mod_name(base::SysMultiByteToWide(module
, CP_ACP
));
94 RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND
, mod_name
, std::wstring());
97 // Using RaiseHardErrorMsg(), it generates the same message box that seen
98 // when the loader cannot find an import a module depends on. |module| is the
99 // DLL name and it cannot be empty. |entry| is the name of the method that
100 // could not be found. The Message box only has an 'ok' button.
101 void EntryPointNotFoundHardError(const char* entry
, const char* module
) {
102 if (!module
|| !entry
)
104 std::wstring
entry_point(base::SysMultiByteToWide(entry
, CP_ACP
));
105 std::wstring
mod_name(base::SysMultiByteToWide(module
, CP_ACP
));
106 RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND
, entry_point
, mod_name
);
109 bool DelayLoadFailureExceptionMessageBox(EXCEPTION_POINTERS
* ex_info
) {
112 DelayLoadInfo
* dli
= reinterpret_cast<DelayLoadInfo
*>(
113 ex_info
->ExceptionRecord
->ExceptionInformation
[0]);
116 if (ex_info
->ExceptionRecord
->ExceptionCode
== kExceptionModuleNotFound
) {
117 ModuleNotFoundHardError(dli
->szDll
);
120 if (ex_info
->ExceptionRecord
->ExceptionCode
== kExceptionEntryPtNotFound
) {
121 if (dli
->dlp
.fImportByName
) {
122 EntryPointNotFoundHardError(dli
->dlp
.szProcName
, dli
->szDll
);