Для пользовательских ошибок вы можете наследовать от std :: exception, переопределять методы исключения и реализовывать свои собственные вещи, например:
#include <exception> // std::exception
//
// custom exception class
//
class error final :
public std::exception
{
public:
error(const char* description, short code = -1) throw() :
description(description), code(code) { }
const char* what() const throw() override
{
return description;
}
short Code() const throw()
{
return code;
}
error(error&& ref)
: description(ref.description), code(ref.code) { }
error& operator=(error&&)
{
return *this;
}
error(const error& ref)
: description(ref.description), code(ref.code) { }
private:
const char* description;
const short code;
error& operator=(const error&) = delete;
};
Определите макрос, чтобы показать имя файла, в котором произошла ошибка:
#include <cstring> // std::strrchr
// Show only file name instead of full path
#define __FILENAME__ (std::strrchr(__FILE__, '\\') ? std::strrchr(__FILE__, '\\') + 1 : __FILE__)
Определение универсальной функции для отображения ошибки (следующая реализация показывает окно сообщения, но вы можете переопределить ее для консольной программы)
#include <string>
#include <windows.h>
#include <codecvt> // string conversion std::wstring_convert and std::codecvt_utf8
//
// converts string or const char* to wstring
//
std::wstring stringToWstring(const std::string& t_str)
{
//setup converter
typedef std::codecvt_utf8<wchar_t> convert_type;
std::wstring_convert<convert_type, wchar_t> converter;
//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
return converter.from_bytes(t_str);
}
//
// Set error message to your liking using error class
// and show message box, this function is also used to pass in
// std::exception objects
//
template <typename ExceptionClass>
void ShowError(
HWND hWnd,
ExceptionClass exception,
const char* file,
int line,
long info = MB_ICONERROR)
{
std::string error_type = TEXT("Rutime Error");
std::string error_message = TEXT("File:\t");
#ifdef UNICODE
error_message.append(stringToWstring(file));
#else
error_message.append(file);
#endif // UNICODE
error_message.append(TEXT("\r\nLine:\t"));
error_message.append(std::to_string(line));
error_message.append(TEXT("\r\nError:\t"));
#ifdef UNICODE
error_message.append(stringToWstring(exception.what()));
#else
error_message.append(exception.what());
#endif // UNICODE
// Show error message
MessageBox(hWnd,
error_message.c_str(),
error_type.c_str(), static_cast<UINT>(MB_OK | info));
}
Затем вы показываете ошибку следующим образом:
ShowError(nullptr, error("You error message"), __FILENAME__, __LINE__);
Для типов ошибок Win32 / COM функция может быть перегружена следующим образом:
#include <comdef.h> // _com_error
#include <windows.h>
#include <string>
//
// Format error code into a string and show message box
// COM and System errors
//
void ShowError(HWND hWnd, const char* file, int line, HRESULT hr = S_OK)
{
string error_type = TEXT("Rutime Error");
string error_message = TEXT("File:\t");
#ifdef UNICODE
error_message.append(stringToWstring(file));
#else
error_message.append(file);
#endif // UNICODE
error_message.append(TEXT("\r\nLine:\t"));
error_message.append(std::to_string(line));
error_message.append(TEXT("\r\nError:\t"));
// If HRESULT is omited or S_OK
// format last error code message
if (hr == S_OK)
{
LPVOID lpBuff = nullptr;
DWORD dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
GetLastError(),
0,
reinterpret_cast<LPTSTR>(&lpBuff),
0,
nullptr);
// If the function succeeds, the return value is
// the number of TCHARs stored in the output buffer
if (dwChars)
{
error_message.append(reinterpret_cast<LPCTSTR>(lpBuff));
}
else // If the function fails, the return value is zero
{
error_message.append(TEXT("Unknown Error\t"));
error_message.append(to_string(GetLastError()));
}
// Free the buffer allocated by FormatMessage
LocalFree(lpBuff);
}
else // Format com error code into a message
{
_com_error err(hr);
error_message.append(err.ErrorMessage());
}
// Play the sound and show error message
MessageBox(hWnd,
error_message.c_str(),
error_type.c_str(), MB_OK | MB_ICONERROR);
}
Функция вызывается незначительно по-разному для системных ошибок:
ShowError(nullptr, __FILENAME__, __LINE__); // type hresult if needed
редактирование:
Я скопировал код из своего проекта, и в настоящее время std::to_string
, где упомянуто, работает только для версии ANSI, вам нужно изменить функцию ShowError
, чтобы условно использовать std::to_wstring
для Unicode.
Также string
внутри функции ShowError является строкой ANSI, вы можете условно использовать wstring
или определить макрос для строки, если вам не нравится это:
#ifdef UNICODE
typedef std::wstring string;
#else
typedef std::string string;
#endif // UNICODE
также для to_string
, если хотите:
// conditionaly use string or wide string
#ifdef UNICODE
#define to_string std::to_wstring
#else
#define to_string std::to_string
#endif // UNICODE
Вы также можете реализовать типы кодов enum class
и передать их в класс исключений в качестве второго или третьего дополнительного аргумента и реализовать отображение пользовательского кода ошибки, если хотите избежать ввода сообщения об ошибке для каждого отдельного вызова функции.
Также обратите внимание, что функцию ShowError
можно использовать для ошибок std внутри оператора catch, где вы просто передаете объект ошибки std, например, такой:
try
{
// example, or do some heavy memory allocation here to throw
throw std::bad_alloc;
}
catch(std::bad_alloc& err);
{
ShowError(nullptr, err, __FILENAME__, __LINE__);
}
Этот подход может быть расширен, чтобы изменить функцию, чтобы также отформатировать NTSTATUS сообщения
Полный список возможных сообщений об ошибках в Win32 см. this .
Для получения дополнительной информации о функциях, используемых в приведенном выше коде, см. Следующую ссылку:
FormatMessage функция
GetLastError функция
Часть кода была скопирована с этого сайта, например:
Преобразовать в строку
Показывать только имя файла
Формат COM Код ошибки