HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
base.hpp
1
2#pragma once
3
5#include "../macros.hpp"
6#include <system_error>
7#include <utility>
8#include <string>
9#include <expected>
10#include <vector>
11#include <algorithm>
12
13hi_export_module(hikogui.win32.errhandlingapi);
14
15namespace hi { inline namespace v1 {
16
17hi_export enum class win32_error : uint32_t {
18 success = ERROR_SUCCESS,
19 file_not_found = ERROR_FILE_NOT_FOUND,
20 more_data = ERROR_MORE_DATA,
21 invalid_data = ERROR_INVALID_DATA,
22};
23
24}} // namespace hi::v1
25
26hi_export template<>
27struct std::is_error_code_enum<hi::win32_error> : std::true_type {};
28
29namespace hi { inline namespace v1 {
30
32 char const *name() const noexcept override
33 {
34 return "win32";
35 }
36
37 std::string message(int code) const override;
38
39 bool equivalent(int code, std::error_condition const & condition) const noexcept override
40 {
41 switch (static_cast<hi::win32_error>(code)) {
42 case hi::win32_error::file_not_found:
43 return condition == std::errc::no_such_file_or_directory;
44 case hi::win32_error::more_data:
45 return condition == std::errc::message_size;
46 case hi::win32_error::invalid_data:
47 return condition == std::errc::bad_message;
48 default:
49 return false;
50 };
51 }
52};
53
54hi_export inline auto global_win32_error_category = win32_error_category{};
55
56hi_export [[nodiscard]] inline std::error_code make_error_code(win32_error code) noexcept
57{
58 return {static_cast<int>(code), global_win32_error_category};
59}
60
61hi_export [[nodiscard]] inline win32_error win32_GetLastError() noexcept
62{
63 return static_cast<win32_error>(::GetLastError());
64}
65
73hi_export [[nodiscard]] inline std::expected<std::string, win32_error> win32_WideCharToMultiByte(std::wstring_view s, unsigned int code_page = CP_UTF8, uint32_t flags = 0) noexcept
74{
75 if (s.empty()) {
76 // WideCharToMultiByte() does not handle empty strings, if it can not also convert the null-character.
77 return std::string{};
78 }
79
80 auto s_len = static_cast<int>(static_cast<unsigned int>(s.size()));
81 auto r_len = ::WideCharToMultiByte(code_page, flags, s.data(), s_len, nullptr, 0, nullptr, nullptr);
82 if (r_len == 0) {
83 return std::unexpected{win32_GetLastError()};
84 }
85
86 auto r = std::string(static_cast<size_t>(static_cast<std::make_signed_t<size_t>>(r_len)), '\0');
87 r.resize_and_overwrite(r_len, [&](char *p, size_t count) {
88 return ::WideCharToMultiByte(code_page, flags, s.data(), s_len, p, static_cast<int>(count), nullptr, nullptr);
89 });
90
91 if (r.empty()) {
92 return std::unexpected{win32_GetLastError()};
93 }
94
95 return r;
96}
97
105hi_export [[nodiscard]] inline std::expected<std::wstring, win32_error> win32_MultiByteToWideChar(std::string_view s, unsigned int code_page = CP_UTF8, uint32_t flags = 0) noexcept
106{
107 if (s.empty()) {
108 // MultiByteToWideChar() does not handle empty strings, if it can not also convert the null-character.
109 return std::wstring{};
110 }
111
112 auto s_len = static_cast<int>(static_cast<unsigned int>(s.size()));
113 auto r_len = ::MultiByteToWideChar(code_page, flags, s.data(), s_len, nullptr, 0);
114 if (r_len == 0) {
115 return std::unexpected{win32_GetLastError()};
116 }
117
118 auto r = std::wstring{};
119 r.resize_and_overwrite(r_len, [&](wchar_t *p, size_t count) {
120 return ::MultiByteToWideChar(code_page, flags, s.data(), s_len, p, static_cast<int>(count));
121 });
122
123 if (r.empty()) {
124 return std::unexpected{win32_GetLastError()};
125 }
126
127 return r;
128}
129
139hi_export [[nodiscard]] inline std::expected<std::vector<std::string>, win32_error> win32_MultiSZToStringVector(wchar_t const *first, wchar_t const *last) noexcept
140{
141 auto r = std::vector<std::string>{};
142
143 while (first != last) {
144 auto it_zero = std::find(first, last, wchar_t{0});
145 if (it_zero == last) {
146 // No termination found.
147 return std::unexpected{win32_error::invalid_data};
148 }
149
150 hilet ws = std::wstring_view{first, static_cast<std::size_t>(it_zero - first)};
151 if (ws.empty()) {
152 // The list is terminated with an empty string.
153 break;
154 }
155
156 if (auto s = win32_WideCharToMultiByte(ws)) {
157 r.push_back(*s);
158 } else {
159 return std::unexpected{s.error()};
160 }
161
162 // Continue after the zero terminator.
163 first = it_zero + 1;
164 }
165
166 return r;
167}
168
169hi_export [[nodiscard]] inline std::expected<std::string, win32_error> win32_FormatMessage(win32_error error_code) noexcept
170{
171 hilet error_code_ = static_cast<DWORD>(std::to_underlying(error_code));
172
173 // FormatMessageW() is unable to tell what the buffer size should be.
174 // But 64Kbyte is the largest buffer that one should pass.
175 LPWSTR buffer = nullptr;
176 hilet result = ::FormatMessageW(
178 NULL, // source
181 reinterpret_cast<LPWSTR>(&buffer),
182 0,
183 NULL);
184
185 if (result == 0) {
186 return std::unexpected(win32_GetLastError());
187 }
188
189 auto r = win32_WideCharToMultiByte(std::wstring_view{buffer, result});
191 return r;
192}
193
194hi_export inline std::string win32_error_category::message(int code) const
195{
196 if (auto msg = win32_FormatMessage(static_cast<win32_error>(code))) {
197 return *msg;
198
199 } else {
200 throw std::system_error(msg.error());
201 }
202}
203
204}} // namespace hi::v1
Rules for working with win32 headers.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
hi_export std::expected< std::string, win32_error > win32_WideCharToMultiByte(std::wstring_view s, unsigned int code_page=CP_UTF8, uint32_t flags=0) noexcept
Convert a win32-API compatible std::wstring to a multi-byte std::string.
Definition base.hpp:73
hi_export std::expected< std::vector< std::string >, win32_error > win32_MultiSZToStringVector(wchar_t const *first, wchar_t const *last) noexcept
Convert a win32 zero terminated list of zero terminated strings.
Definition base.hpp:139
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
hi_export std::expected< std::wstring, win32_error > win32_MultiByteToWideChar(std::string_view s, unsigned int code_page=CP_UTF8, uint32_t flags=0) noexcept
Convert a win32-API compatible std::wstring to a multi-byte std::string.
Definition base.hpp:105
Definition base.hpp:31
T find(T... args)
T unexpected(T... args)