Created
January 27, 2017 14:54
-
-
Save bbolli/710010adb309d5063111889530237d6d to your computer and use it in GitHub Desktop.
A C++11 std::error_category for Win32 and Winsock error codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <system_error> | |
#include <windows.h> | |
/// Wrap the Win32 error code so we have a distinct type. | |
struct win32_error_code | |
{ | |
explicit win32_error_code(DWORD e) noexcept : error(e) {} | |
DWORD error; | |
}; | |
namespace detail | |
{ | |
/// The Win32 error code category. | |
class win32_error_category : public std::error_category | |
{ | |
public: | |
/// Return a short descriptive name for the category. | |
char const* name() const noexcept override final { return "Win32Error"; } | |
/// Return what each error code means in text. | |
std::string message(int c) const override final | |
{ | |
char error[256]; | |
auto len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, | |
static_cast<DWORD>(c), 0, error, sizeof error, | |
NULL); | |
if (len == 0) | |
return "N/A"; | |
// trim trailing newline | |
while (len && (error[len - 1] == '\r' || error[len - 1] == '\n')) | |
--len; | |
return std::string(error, len); | |
} | |
}; | |
} | |
/// Return a static instance of the custom category. | |
extern detail::win32_error_category const& win32_error_category() | |
{ | |
static detail::win32_error_category c; | |
return c; | |
} | |
// Overload the global make_error_code() free function with our | |
// custom error. It will be found via ADL by the compiler if needed. | |
inline std::error_code make_error_code(win32_error_code const& we) | |
{ | |
return std::error_code(static_cast<int>(we.error), win32_error_category()); | |
} | |
/// Create an error_code from a Windows error code. | |
inline std::error_code make_win32_error_code(DWORD e) | |
{ | |
return make_error_code(win32_error_code(e)); | |
} | |
/// Create an error_code from the last Windows error. | |
inline std::error_code make_win32_error_code() | |
{ | |
return make_win32_error_code(GetLastError()); | |
} | |
/// Create an error_code from the last Winsock error. | |
inline std::error_code make_winsock_error_code() | |
{ | |
return make_win32_error_code(WSAGetLastError()); | |
} | |
namespace std | |
{ | |
// Tell the C++ 11 STL metaprogramming that win32_error_code | |
// is registered with the standard error code system. | |
template <> | |
struct is_error_code_enum<win32_error_code> : std::true_type {}; | |
} | |
// --------------------------------------------------------------------- | |
// A small demo program follows | |
#include <iostream> | |
int main(int, char** argv) | |
{ | |
auto decode = [](DWORD e) { | |
auto ec = make_win32_error_code(e); | |
std::cout << e << " is printed by std::error_code as " << ec | |
<< " with explanatory message\n'" << ec.message() << "'\n"; | |
}; | |
// display the Win32 error codes given on the command line | |
while (*++argv) | |
decode(strtoul(*argv, NULL, 0)); | |
// send some data to a non-socket | |
WSADATA wsa; | |
WSAStartup(0x0101, &wsa); | |
if (send(42, "abc", 3, 0) < 3) | |
std::cerr << make_winsock_error_code().message() << '\n'; | |
if (WSACleanup() == SOCKET_ERROR) | |
std::cerr << make_winsock_error_code().message() << '\n'; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment