mirror of
https://github.com/reactos/reactos.git
synced 2025-06-29 12:51:25 +00:00

Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3 License: MIT
200 lines
5.6 KiB
C++
200 lines
5.6 KiB
C++
/***
|
|
*report_runtime_error.cpp - startup error messages
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* Prints out banner for runtime error messages.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <corecrt_internal.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
// This is used during the expansion of the runtime error text.
|
|
#define EOL L"\r\n"
|
|
|
|
static bool __cdecl issue_debug_notification(wchar_t const* const message) throw()
|
|
{
|
|
// This is referenced only in the Debug CRT build
|
|
UNREFERENCED_PARAMETER(message);
|
|
|
|
#ifdef _DEBUG
|
|
switch (_CrtDbgReportW(_CRT_ERROR, nullptr, 0, nullptr, L"%ls", message))
|
|
{
|
|
case 1:
|
|
_CrtDbgBreak();
|
|
return true;
|
|
|
|
case 0:
|
|
return true;
|
|
}
|
|
#endif // _DEBUG
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enclaves do not support error messages outside of OutputDebugString.
|
|
#ifdef _UCRT_ENCLAVE_BUILD
|
|
|
|
extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
|
|
{
|
|
// Report the error using the debug
|
|
issue_debug_notification(message);
|
|
}
|
|
|
|
#else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
|
|
|
|
/*
|
|
* __acrt_app_type, together with __error_mode, determine how error messages
|
|
* are written out.
|
|
*/
|
|
static _crt_app_type __acrt_app_type = _crt_unknown_app;
|
|
|
|
/***
|
|
*void _set_app_type(int apptype) - interface to change __acrt_app_type
|
|
*
|
|
*Purpose:
|
|
* Set, or change, the value of __acrt_app_type.
|
|
*
|
|
* Set the default debug lib report destination for console apps.
|
|
*
|
|
* This function is for INTERNAL USE ONLY.
|
|
*
|
|
*Entry:
|
|
* int modeval = _crt_unknown_app, unknown
|
|
* _crt_console_app, console, or command line, application
|
|
* _crt_gui_app, GUI, or Windows, application
|
|
*
|
|
*Exit:
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
extern "C" void __cdecl _set_app_type(_crt_app_type const new_app_type)
|
|
{
|
|
__acrt_app_type = new_app_type;
|
|
}
|
|
|
|
extern "C" _crt_app_type __cdecl _query_app_type()
|
|
{
|
|
return __acrt_app_type;
|
|
}
|
|
|
|
|
|
|
|
static bool __cdecl should_write_error_to_console() throw()
|
|
{
|
|
int const error_mode = _set_error_mode(_REPORT_ERRMODE);
|
|
|
|
if (error_mode == _OUT_TO_STDERR)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (error_mode == _OUT_TO_DEFAULT && __acrt_app_type == _crt_console_app)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
static void write_string_to_console(wchar_t const* const wide_string) throw()
|
|
{
|
|
HANDLE const handle = GetStdHandle(STD_ERROR_HANDLE);
|
|
if (handle == nullptr || handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// We convert the wide string to a narrow string by truncating each character.
|
|
// Currently, the text for each runtime error consists only of ASCII, so this
|
|
// is acceptable. If the error text is ever localized, this would need to
|
|
// change.
|
|
size_t const narrow_buffer_count = 500;
|
|
char narrow_buffer[narrow_buffer_count];
|
|
|
|
char* const narrow_first = narrow_buffer;
|
|
char* const narrow_last = narrow_first + narrow_buffer_count;
|
|
|
|
// Note that this loop copies the null terminator if the loop terminates
|
|
// befoe running out of buffer space:
|
|
char* narrow_it = narrow_first;
|
|
wchar_t const* wide_it = wide_string;
|
|
do
|
|
{
|
|
*narrow_it = static_cast<char>(*wide_it);
|
|
}
|
|
while (++narrow_it != narrow_last && *wide_it++ != '\0');
|
|
|
|
// If we did run out of buffer space, this will null-terminate the text that
|
|
// we were able to copy:
|
|
*(narrow_last - 1) = '\0';
|
|
|
|
DWORD const bytes_to_write = static_cast<DWORD>(narrow_it - narrow_first - 1); // Account for null terminator
|
|
DWORD bytes_written = 0;
|
|
WriteFile(handle, narrow_buffer, bytes_to_write, &bytes_written, nullptr);
|
|
}
|
|
|
|
|
|
|
|
extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
|
|
{
|
|
// Before we report the error via the normal path, report the error using
|
|
// the debug
|
|
if (issue_debug_notification(message))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (should_write_error_to_console())
|
|
{
|
|
write_string_to_console(message);
|
|
}
|
|
else
|
|
{
|
|
#define MSGTEXTPREFIX L"Runtime Error!\n\nProgram: "
|
|
static wchar_t outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) + _MAX_PATH + 2 + 500];
|
|
// runtime error msg + progname + 2 newline + runtime error text.
|
|
wchar_t* progname = &outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) - 1];
|
|
size_t progname_size = _countof(outmsg) - (progname - outmsg);
|
|
wchar_t* pch = progname;
|
|
|
|
_ERRCHECK(wcscpy_s(outmsg, _countof(outmsg), MSGTEXTPREFIX));
|
|
|
|
progname[MAX_PATH] = L'\0';
|
|
if (!GetModuleFileNameW(nullptr, progname, MAX_PATH))
|
|
{
|
|
_ERRCHECK(wcscpy_s(progname, progname_size, L"<program name unknown>"));
|
|
}
|
|
|
|
#define MAXLINELEN 60
|
|
if (wcslen(pch) + 1 > MAXLINELEN)
|
|
{
|
|
pch += wcslen(progname) + 1 - MAXLINELEN;
|
|
_ERRCHECK(wcsncpy_s(pch, progname_size - (pch - progname), L"...", 3));
|
|
}
|
|
|
|
_ERRCHECK(wcscat_s(outmsg, _countof(outmsg), L"\n\n"));
|
|
_ERRCHECK(wcscat_s(outmsg, _countof(outmsg), message));
|
|
|
|
// Okay to ignore return value here, this is just to display the message box.
|
|
// Only caller is abort() (so we shouldn't/can't handle IDABORT), so the process
|
|
// will end shortly.
|
|
__acrt_show_wide_message_box(
|
|
outmsg,
|
|
L"Microsoft Visual C++ Runtime Library",
|
|
MB_OK | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL);
|
|
}
|
|
}
|
|
|
|
#endif /* _UCRT_ENCLAVE_BUILD */
|