Echo Writes Code

windows_error.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "crucible/windows/windows_error.hpp"

#include "crucible/windows/transcoding.hpp"

#include <Windows.h>

#include <memory>
#include <sstream>
#include <type_traits>

namespace crucible::windows::windows_error {
  template<typename T>
  class LocalFreeDeleter {
    static_assert(std::is_pointer_v<T>);

  public:
    LocalFreeDeleter(T pointer) :
      my_pointer(pointer) {
    }

    ~LocalFreeDeleter() {
      if (my_pointer) {
        ::LocalFree(my_pointer);
      }
    }

  private:
    T my_pointer = nullptr;
  };

  auto get_windows_error_code() -> std::uint32_t {
    ::DWORD const error_code = ::GetLastError();

    static_assert(sizeof(::DWORD) <= sizeof(std::uint32_t));
    static_assert(std::is_unsigned_v<::DWORD> == std::is_unsigned_v<std::uint32_t>);
    return static_cast<std::uint32_t>(error_code);
  }

  auto format_windows_error_code(std::uint32_t const error_code) -> std::string {
    constexpr ::DWORD FLAGS = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK;
    constexpr ::DWORD LANGUAGE_ID = 0;
    constexpr ::DWORD MINIMUM_SIZE = 0;

    ::LPVOID message_source = nullptr;
    ::LPWSTR raw_utf16_message = nullptr;
    auto dont_blame_me_blame_microsoft = reinterpret_cast<::LPWSTR>(&raw_utf16_message);
    ::va_list *arguments = nullptr;

    ::DWORD const characters_written = ::FormatMessageW(FLAGS, message_source, error_code, LANGUAGE_ID, dont_blame_me_blame_microsoft, MINIMUM_SIZE, arguments);
    if (characters_written == 0) {
      ::DWORD const cause = ::GetLastError();
      std::ostringstream buffer;

      buffer
        << "Failed to format message for Windows API error code `" << error_code << "`"
        << " "
        << "(Error code returned from FormatMessageW() was: `" << cause << "`)";

      return buffer.str();
    }

    LocalFreeDeleter<::LPWSTR> deleter(raw_utf16_message);

    ::DWORD const characters_written_excluding_terminator = characters_written - 1;
    std::wstring const utf16_message(raw_utf16_message, characters_written_excluding_terminator);

    auto const transcoding_result = transcoding::transcode_utf16_to_utf8(utf16_message);
    if (transcoding_result.has_failure()) {
      std::ostringstream buffer;
      buffer << "Failed to transcode Windows API error message from UTF16 to UTF8 for error code `" << error_code << "`";
      return buffer.str();
    }

    return std::move(transcoding_result).get_success();
  }
}