File indexing completed on 2025-09-18 08:53:39
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_WIN32_CODE_HPP
0032 #define BOOST_OUTCOME_SYSTEM_ERROR2_WIN32_CODE_HPP
0033
0034 #if !defined(_WIN32) && !defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0035 #error This file should only be included on Windows
0036 #endif
0037
0038 #include "quick_status_code_from_enum.hpp"
0039
0040 #if defined(_MSC_VER) && !defined(__clang__)
0041 #pragma warning(push)
0042 #pragma warning(disable : 6326)
0043 #endif
0044
0045 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
0046
0047
0048 namespace win32
0049 {
0050 #ifdef __MINGW32__
0051 extern "C"
0052 {
0053 #endif
0054
0055 using DWORD = unsigned long;
0056
0057 extern DWORD __stdcall GetLastError();
0058
0059 extern DWORD __stdcall FormatMessageW(DWORD dwFlags, const void *lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t *lpBuffer, DWORD nSize,
0060 void *Arguments);
0061
0062 extern int __stdcall WideCharToMultiByte(unsigned int CodePage, DWORD dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr,
0063 int cbMultiByte, const char *lpDefaultChar, int *lpUsedDefaultChar);
0064 #ifdef __MINGW32__
0065 }
0066 #else
0067 #pragma comment(lib, "kernel32.lib")
0068 #if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64))
0069 #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError")
0070 #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPEBXKKPEA_WKPEAX@Z=FormatMessageW")
0071 #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPEB_WHPEADHPEBDPEAH@Z=WideCharToMultiByte")
0072 #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
0073 #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YGKXZ=_GetLastError@0")
0074 #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YGKKPBXKKPA_WKPAX@Z=_FormatMessageW@28")
0075 #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YGHIKPB_WHPADHPBDPAH@Z=_WideCharToMultiByte@32")
0076 #elif defined(__arm__) || defined(_M_ARM)
0077 #pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError")
0078 #pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPBXKKPA_WKPAX@Z=FormatMessageW")
0079 #pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPB_WHPADHPBDPAH@Z=WideCharToMultiByte")
0080 #else
0081 #error Unknown architecture
0082 #endif
0083 #endif
0084 }
0085
0086 class _win32_code_domain;
0087 class _com_code_domain;
0088
0089 using win32_code = status_code<_win32_code_domain>;
0090
0091 using win32_error = status_error<_win32_code_domain>;
0092
0093 namespace mixins
0094 {
0095 template <class Base> struct mixin<Base, _win32_code_domain> : public Base
0096 {
0097 using Base::Base;
0098
0099
0100 static inline win32_code current() noexcept;
0101 };
0102 }
0103
0104
0105
0106 class _win32_code_domain : public status_code_domain
0107 {
0108 template <class DomainType> friend class status_code;
0109 friend class _com_code_domain;
0110 using _base = status_code_domain;
0111 static int _win32_code_to_errno(win32::DWORD c)
0112 {
0113 switch(c)
0114 {
0115 case 0:
0116 return 0;
0117 #include "detail/win32_code_to_generic_code.ipp"
0118 }
0119 return -1;
0120 }
0121
0122 static _base::string_ref _make_string_ref(win32::DWORD c) noexcept
0123 {
0124 wchar_t buffer[32768];
0125 win32::DWORD wlen =
0126 win32::FormatMessageW(0x00001000 | 0x00000200 , nullptr, c, 0, buffer, 32768, nullptr);
0127 size_t allocation = wlen + (wlen >> 1);
0128 win32::DWORD bytes;
0129 if(wlen == 0)
0130 {
0131 return _base::string_ref("failed to get message from system");
0132 }
0133 for(;;)
0134 {
0135 auto *p = static_cast<char *>(malloc(allocation));
0136 if(p == nullptr)
0137 {
0138 return _base::string_ref("failed to get message from system");
0139 }
0140 bytes = win32::WideCharToMultiByte(65001 , 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
0141 if(bytes != 0)
0142 {
0143 char *end = strchr(p, 0);
0144 while(end[-1] == 10 || end[-1] == 13)
0145 {
0146 --end;
0147 }
0148 *end = 0;
0149 return _base::atomic_refcounted_string_ref(p, end - p);
0150 }
0151 free(p);
0152 if(win32::GetLastError() == 0x7a )
0153 {
0154 allocation += allocation >> 2;
0155 continue;
0156 }
0157 return _base::string_ref("failed to get message from system");
0158 }
0159 }
0160
0161 public:
0162
0163 using value_type = win32::DWORD;
0164 using _base::string_ref;
0165
0166 public:
0167
0168 constexpr explicit _win32_code_domain(typename _base::unique_id_type id = 0x8cd18ee72d680f1b) noexcept
0169 : _base(id)
0170 {
0171 }
0172 _win32_code_domain(const _win32_code_domain &) = default;
0173 _win32_code_domain(_win32_code_domain &&) = default;
0174 _win32_code_domain &operator=(const _win32_code_domain &) = default;
0175 _win32_code_domain &operator=(_win32_code_domain &&) = default;
0176 ~_win32_code_domain() = default;
0177
0178
0179 static inline constexpr const _win32_code_domain &get();
0180
0181 virtual string_ref name() const noexcept override { return string_ref("win32 domain"); }
0182
0183 virtual payload_info_t payload_info() const noexcept override
0184 {
0185 return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
0186 (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
0187 }
0188
0189 protected:
0190 virtual bool _do_failure(const status_code<void> &code) const noexcept override
0191 {
0192 assert(code.domain() == *this);
0193 return static_cast<const win32_code &>(code).value() != 0;
0194 }
0195 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override
0196 {
0197 assert(code1.domain() == *this);
0198 const auto &c1 = static_cast<const win32_code &>(code1);
0199 if(code2.domain() == *this)
0200 {
0201 const auto &c2 = static_cast<const win32_code &>(code2);
0202 return c1.value() == c2.value();
0203 }
0204 if(code2.domain() == generic_code_domain)
0205 {
0206 const auto &c2 = static_cast<const generic_code &>(code2);
0207 if(static_cast<int>(c2.value()) == _win32_code_to_errno(c1.value()))
0208 {
0209 return true;
0210 }
0211 }
0212 return false;
0213 }
0214 virtual generic_code _generic_code(const status_code<void> &code) const noexcept override
0215 {
0216 assert(code.domain() == *this);
0217 const auto &c = static_cast<const win32_code &>(code);
0218 return generic_code(static_cast<errc>(_win32_code_to_errno(c.value())));
0219 }
0220 virtual string_ref _do_message(const status_code<void> &code) const noexcept override
0221 {
0222 assert(code.domain() == *this);
0223 const auto &c = static_cast<const win32_code &>(code);
0224 return _make_string_ref(c.value());
0225 }
0226 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0227 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override
0228 {
0229 assert(code.domain() == *this);
0230 const auto &c = static_cast<const win32_code &>(code);
0231 throw status_error<_win32_code_domain>(c);
0232 }
0233 #endif
0234 };
0235
0236
0237 constexpr _win32_code_domain win32_code_domain;
0238 inline constexpr const _win32_code_domain &_win32_code_domain::get()
0239 {
0240 return win32_code_domain;
0241 }
0242
0243 namespace mixins
0244 {
0245 template <class Base> inline win32_code mixin<Base, _win32_code_domain>::current() noexcept
0246 {
0247 return win32_code(win32::GetLastError());
0248 }
0249 }
0250
0251 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
0252
0253 #if defined(_MSC_VER) && !defined(__clang__)
0254 #pragma warning(pop)
0255 #endif
0256
0257 #endif