winapi_common
error.cpp
1 // Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com>
2 // This file is part of the "winapi-common" project.
3 // For details, see https://github.com/egor-tensin/winapi-common.
4 // Distributed under the MIT License.
5 
6 #include <winapi/error.hpp>
7 #include <winapi/utf8.hpp>
8 
9 #include <windows.h>
10 
11 #include <cstdint>
12 #include <sstream>
13 #include <string>
14 #include <system_error>
15 
16 namespace winapi {
17 namespace error {
18 namespace {
19 
20 std::wstring trim_trailing_newline(const std::wstring& s) {
21  const auto last_pos = s.find_last_not_of(L"\r\n");
22  if (std::wstring::npos == last_pos)
23  return {};
24  return s.substr(0, last_pos + 1);
25 }
26 
27 std::string build_what(DWORD code, const char* function) {
28  std::ostringstream what;
29  what << "Function " << function << " failed with error code " << code;
30  return what.str();
31 }
32 
33 std::string format_message(int32_t code) {
34  wchar_t* buf;
35 
36  const auto len = ::FormatMessageW(
37  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
38  NULL,
39  code,
40  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
41  reinterpret_cast<wchar_t*>(&buf),
42  0,
43  NULL);
44 
45  if (0 == len) {
46  ::LocalFree(buf);
47  return "Couldn't format the error message";
48  }
49 
50  std::wstring msg{buf, len};
51  ::LocalFree(buf);
52  return narrow(trim_trailing_newline(msg));
53 }
54 
55 } // namespace
56 
57 std::string CategoryWindows::message(int32_t code) const {
58  return format_message(code);
59 }
60 
61 std::system_error windows(DWORD code, const char* function) {
62  static_assert(sizeof(DWORD) == sizeof(int32_t), "Aren't DWORDs the same size as ints?");
63  return std::system_error{
64  static_cast<int32_t>(code), category_windows(), build_what(code, function)};
65 }
66 
67 } // namespace error
68 } // namespace winapi
Make std::system_error work with GetLastError().
std::system_error windows(DWORD code, const char *function)
Definition: error.cpp:61