File indexing completed on 2025-09-15 08:43: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_NT_CODE_HPP
0032 #define BOOST_OUTCOME_SYSTEM_ERROR2_NT_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 "win32_code.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 NTSTATUS = long;
0056
0057 using HMODULE = void *;
0058
0059 extern HMODULE __stdcall GetModuleHandleW(const wchar_t *lpModuleName);
0060 #ifdef __MINGW32__
0061 }
0062 #else
0063 #pragma comment(lib, "kernel32.lib")
0064 #if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64))
0065 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPEAXPEB_W@Z=GetModuleHandleW")
0066 #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
0067 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YGPAXPB_W@Z=_GetModuleHandleW@4")
0068 #elif defined(__arm__) || defined(_M_ARM)
0069 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPAXPB_W@Z=GetModuleHandleW")
0070 #else
0071 #error Unknown architecture
0072 #endif
0073 #endif
0074 }
0075
0076 class _nt_code_domain;
0077
0078 using nt_code = status_code<_nt_code_domain>;
0079
0080 using nt_error = status_error<_nt_code_domain>;
0081
0082
0083
0084 class _nt_code_domain : public status_code_domain
0085 {
0086 template <class DomainType> friend class status_code;
0087 friend class _com_code_domain;
0088 using _base = status_code_domain;
0089 static int _nt_code_to_errno(win32::NTSTATUS c)
0090 {
0091 if(c >= 0)
0092 {
0093 return 0;
0094 }
0095 switch(static_cast<unsigned>(c))
0096 {
0097 #include "detail/nt_code_to_generic_code.ipp"
0098 }
0099 return -1;
0100 }
0101 static win32::DWORD _nt_code_to_win32_code(win32::NTSTATUS c)
0102 {
0103 if(c >= 0)
0104 {
0105 return 0;
0106 }
0107 switch(static_cast<unsigned>(c))
0108 {
0109 #include "detail/nt_code_to_win32_code.ipp"
0110 }
0111 return static_cast<win32::DWORD>(-1);
0112 }
0113
0114 static _base::string_ref _make_string_ref(win32::NTSTATUS c) noexcept
0115 {
0116 wchar_t buffer[32768];
0117 static win32::HMODULE ntdll = win32::GetModuleHandleW(L"NTDLL.DLL");
0118 win32::DWORD wlen =
0119 win32::FormatMessageW(0x00000800 | 0x00001000 | 0x00000200 ,
0120 ntdll, c, (1 << 10) , buffer, 32768, nullptr);
0121 size_t allocation = wlen + (wlen >> 1);
0122 win32::DWORD bytes;
0123 if(wlen == 0)
0124 {
0125 return _base::string_ref("failed to get message from system");
0126 }
0127 for(;;)
0128 {
0129 auto *p = static_cast<char *>(malloc(allocation));
0130 if(p == nullptr)
0131 {
0132 return _base::string_ref("failed to get message from system");
0133 }
0134 bytes = win32::WideCharToMultiByte(65001 , 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
0135 if(bytes != 0)
0136 {
0137 char *end = strchr(p, 0);
0138 while(end[-1] == 10 || end[-1] == 13)
0139 {
0140 --end;
0141 }
0142 *end = 0;
0143 return _base::atomic_refcounted_string_ref(p, end - p);
0144 }
0145 free(p);
0146 if(win32::GetLastError() == 0x7a )
0147 {
0148 allocation += allocation >> 2;
0149 continue;
0150 }
0151 return _base::string_ref("failed to get message from system");
0152 }
0153 }
0154
0155 public:
0156
0157 using value_type = win32::NTSTATUS;
0158 using _base::string_ref;
0159
0160 public:
0161
0162 constexpr explicit _nt_code_domain(typename _base::unique_id_type id = 0x93f3b4487e4af25b) noexcept
0163 : _base(id)
0164 {
0165 }
0166 _nt_code_domain(const _nt_code_domain &) = default;
0167 _nt_code_domain(_nt_code_domain &&) = default;
0168 _nt_code_domain &operator=(const _nt_code_domain &) = default;
0169 _nt_code_domain &operator=(_nt_code_domain &&) = default;
0170 ~_nt_code_domain() = default;
0171
0172
0173 static inline constexpr const _nt_code_domain &get();
0174
0175 virtual string_ref name() const noexcept override { return string_ref("NT domain"); }
0176
0177 virtual payload_info_t payload_info() const noexcept override
0178 {
0179 return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
0180 (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
0181 }
0182
0183 protected:
0184 virtual bool _do_failure(const status_code<void> &code) const noexcept override
0185 {
0186 assert(code.domain() == *this);
0187 return static_cast<const nt_code &>(code).value() < 0;
0188 }
0189 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override
0190 {
0191 assert(code1.domain() == *this);
0192 const auto &c1 = static_cast<const nt_code &>(code1);
0193 if(code2.domain() == *this)
0194 {
0195 const auto &c2 = static_cast<const nt_code &>(code2);
0196 return c1.value() == c2.value();
0197 }
0198 if(code2.domain() == generic_code_domain)
0199 {
0200 const auto &c2 = static_cast<const generic_code &>(code2);
0201 if(static_cast<int>(c2.value()) == _nt_code_to_errno(c1.value()))
0202 {
0203 return true;
0204 }
0205 }
0206 if(code2.domain() == win32_code_domain)
0207 {
0208 const auto &c2 = static_cast<const win32_code &>(code2);
0209 if(c2.value() == _nt_code_to_win32_code(c1.value()))
0210 {
0211 return true;
0212 }
0213 }
0214 return false;
0215 }
0216 virtual generic_code _generic_code(const status_code<void> &code) const noexcept override
0217 {
0218 assert(code.domain() == *this);
0219 const auto &c = static_cast<const nt_code &>(code);
0220 return generic_code(static_cast<errc>(_nt_code_to_errno(c.value())));
0221 }
0222 virtual string_ref _do_message(const status_code<void> &code) const noexcept override
0223 {
0224 assert(code.domain() == *this);
0225 const auto &c = static_cast<const nt_code &>(code);
0226 return _make_string_ref(c.value());
0227 }
0228 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0229 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override
0230 {
0231 assert(code.domain() == *this);
0232 const auto &c = static_cast<const nt_code &>(code);
0233 throw status_error<_nt_code_domain>(c);
0234 }
0235 #endif
0236 };
0237
0238 constexpr _nt_code_domain nt_code_domain;
0239 inline constexpr const _nt_code_domain &_nt_code_domain::get()
0240 {
0241 return nt_code_domain;
0242 }
0243
0244 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
0245
0246 #if defined(_MSC_VER) && !defined(__clang__)
0247 #pragma warning(pop)
0248 #endif
0249
0250 #endif