// C++/WinRT v2.0.250303.1 // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #define CPPWINRT_VERSION "2.0.250303.1" #pragma once #ifndef WINRT_BASE_H #define WINRT_BASE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __has_include() #include #endif #if __has_include() #define WINRT_IMPL_NUMERICS #include #endif #ifndef WINRT_LEAN_AND_MEAN #include #endif #ifdef __cpp_lib_span #include #endif #ifdef __cpp_lib_format #include #endif #ifdef __cpp_lib_source_location #include #endif #ifdef __cpp_lib_coroutine #include namespace winrt::impl { template using coroutine_handle = std::coroutine_handle; using suspend_always = std::suspend_always; using suspend_never = std::suspend_never; } #elif __has_include() #include namespace winrt::impl { template using coroutine_handle = std::experimental::coroutine_handle; using suspend_always = std::experimental::suspend_always; using suspend_never = std::experimental::suspend_never; } #else #error C++/WinRT requires coroutine support, which is currently missing. Try enabling C++20 in your compiler. #endif #ifdef _DEBUG #define WINRT_ASSERT _ASSERTE #define WINRT_VERIFY WINRT_ASSERT #define WINRT_VERIFY_(result, expression) WINRT_ASSERT(result == expression) #else #define WINRT_ASSERT(expression) ((void)0) #define WINRT_VERIFY(expression) (void)(expression) #define WINRT_VERIFY_(result, expression) (void)(expression) #endif #define WINRT_IMPL_SHIM(...) (*(abi_t<__VA_ARGS__>**)&static_cast<__VA_ARGS__ const&>(static_cast(*this))) #ifdef _MSC_VER // Note: this is a workaround for a false-positive warning produced by the Visual C++ 15.9 compiler. #pragma warning(disable : 5046) // Note: this is a workaround for a false-positive warning produced by the Visual C++ 16.3 compiler. #pragma warning(disable : 4268) #endif #if defined(__cpp_lib_coroutine) || defined(__cpp_coroutines) || defined(_RESUMABLE_FUNCTIONS_SUPPORTED) #define WINRT_IMPL_COROUTINES #endif #ifndef WINRT_EXPORT #define WINRT_EXPORT #endif #ifdef WINRT_IMPL_NUMERICS #define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics #define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics #define _WINDOWS_NUMERICS_END_NAMESPACE_ #include #undef _WINDOWS_NUMERICS_NAMESPACE_ #undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ #undef _WINDOWS_NUMERICS_END_NAMESPACE_ #endif #if defined(_MSC_VER) #define WINRT_IMPL_NOINLINE __declspec(noinline) #elif defined(__GNUC__) #define WINRT_IMPL_NOINLINE __attribute__((noinline)) #else #define WINRT_IMPL_NOINLINE #endif #if defined(_MSC_VER) #define WINRT_IMPL_EMPTY_BASES __declspec(empty_bases) #else #define WINRT_IMPL_EMPTY_BASES #endif #if defined(_MSC_VER) #define WINRT_IMPL_NOVTABLE __declspec(novtable) #else #define WINRT_IMPL_NOVTABLE #endif #if defined(__clang__) #define WINRT_IMPL_HAS_DECLSPEC_UUID __has_declspec_attribute(uuid) #elif defined(_MSC_VER) #define WINRT_IMPL_HAS_DECLSPEC_UUID 1 #else #define WINRT_IMPL_HAS_DECLSPEC_UUID 0 #endif #ifdef __IUnknown_INTERFACE_DEFINED__ #define WINRT_IMPL_IUNKNOWN_DEFINED #else // Forward declare so we can talk about it. struct IUnknown; typedef struct _GUID GUID; #endif #if defined(__cpp_consteval) #define WINRT_IMPL_CONSTEVAL consteval #else #define WINRT_IMPL_CONSTEVAL constexpr #endif // The intrinsics (such as __builtin_FILE()) that power std::source_location are also used to power winrt:impl::slim_source_location. // The source location needs to be for the calling code, not cppwinrt itself, so that it is useful to developers building on top of // this library. As a result any public-facing method that can result in an error needs a default-constructed slim_source_location // argument so that it will collect source information from the application code that is calling into cppwinrt. // // We do not directly use std::source_location for two reasons: // 1) std::source_location::function_name() is unavoidable. These strings end up in the final binary, bloating their size. This // is particularly impactful for code bases that use templates heavily. Cases of 50% binary size growth have been observed. // 2) std::source_location is a cpp20 feature, which is above the cpp17 feature floor for cppwinrt. By defining our own version // we can avoid ODR violations in mixed cpp17/cpp20 builds. cpp17 callers will have an ABI that matches cpp20 callers (they // will just not have useful file/line/function information). // // Some projects may decide that the source information binary size impact is not worth the benefit. Defining WINRT_NO_SOURCE_LOCATION // will prevent this feature from activating. The slim_source_location type will be forwarded around but it will not include any // nonzero data. That eliminates the biggest source of binary size overhead. // // To help with debugging the __builtin_FUNCTION() intrinsic will be used in _DEBUG builds. This will provide a bit more diagnostic // value at the cost of binary size. The assumption is that binary size is considered less important in debug builds so this tradeoff // is acceptable. // // The different behavior of the default parameters to winrt::impl::slim_source_location::current() is technically an ODR violation, // albeit a minor one. There should be no serious consequence to this violation. In practice it means that mixing cpp17/cpp20, // or mixing WINRT_NO_SOURCE_LOCATION with undefining it, will lead to inconsistent source location information. It may be missing // when it is expected to be included, or it may be present when it is not expected. The behavior will depend on the linker's choice // when there are multiple translation units with different options. This violation is tracked by https://github.com/microsoft/cppwinrt/issues/1445. #if !defined(__cpp_lib_source_location) || defined(WINRT_NO_SOURCE_LOCATION) // Case1: cpp17 mode. The source_location intrinsics are not available. // Case2: The caller has disabled source_location support. Ensure that there is no binary size overhead for line/file/function. #define WINRT_IMPL_BUILTIN_LINE 0 #define WINRT_IMPL_BUILTIN_FILE nullptr #define WINRT_IMPL_BUILTIN_FUNCTION nullptr #elif _DEBUG // cpp20 _DEBUG builds include function information, which has a heavy binary size impact, in addition to file/line. #define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() #define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() #define WINRT_IMPL_BUILTIN_FUNCTION __builtin_FUNCTION() #else // Release builds in cpp20 mode get file and line information but NOT function information. Function strings // quickly add up to a substantial binary size impact, especially when templates are heavily used. #define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() #define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() #define WINRT_IMPL_BUILTIN_FUNCTION nullptr #endif namespace winrt::impl { // This struct is intended to be highly similar to std::source_location. The key difference is // that function_name is NOT included. Function names do not fold to identical strings and can // have heavy binary size overhead when templates cause many permutations to exist. struct slim_source_location { [[nodiscard]] static WINRT_IMPL_CONSTEVAL slim_source_location current( const std::uint_least32_t line = WINRT_IMPL_BUILTIN_LINE, const char* const file = WINRT_IMPL_BUILTIN_FILE, const char* const function = WINRT_IMPL_BUILTIN_FUNCTION) noexcept { return slim_source_location{ line, file, function }; } [[nodiscard]] constexpr slim_source_location() noexcept = default; [[nodiscard]] constexpr slim_source_location( const std::uint_least32_t line, const char* const file, const char* const function) noexcept : m_line(line), m_file(file), m_function(function) {} [[nodiscard]] constexpr std::uint_least32_t line() const noexcept { return m_line; } [[nodiscard]] constexpr const char* file_name() const noexcept { return m_file; } [[nodiscard]] constexpr const char* function_name() const noexcept { return m_function; } private: const std::uint_least32_t m_line{}; const char* const m_file{}; const char* const m_function{}; }; } #ifdef _MSC_VER #pragma detect_mismatch("WINRT_SOURCE_LOCATION", "slim") #endif // _MSC_VER namespace winrt::impl { using ptp_io = struct tp_io*; using ptp_timer = struct tp_timer*; using ptp_wait = struct tp_wait*; using ptp_pool = struct tp_pool*; using srwlock = struct srwlock_*; using condition_variable = struct condition_variable_*; using bstr = wchar_t*; using filetime_period = std::ratio_multiply, std::nano>; struct IAgileObject; struct com_callback_args { uint32_t reserved1; uint32_t reserved2; void* data; }; template constexpr uint8_t hex_to_uint(T const c) { if (c >= '0' && c <= '9') { return static_cast(c - '0'); } else if (c >= 'A' && c <= 'F') { return static_cast(10 + c - 'A'); } else if (c >= 'a' && c <= 'f') { return static_cast(10 + c - 'a'); } else { throw std::invalid_argument("Character is not a hexadecimal digit"); } } template constexpr uint8_t hex_to_uint8(T const a, T const b) { return (hex_to_uint(a) << 4) | hex_to_uint(b); } constexpr uint16_t uint8_to_uint16(uint8_t a, uint8_t b) { return (static_cast(a) << 8) | static_cast(b); } constexpr uint32_t uint8_to_uint32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { return (static_cast(uint8_to_uint16(a, b)) << 16) | static_cast(uint8_to_uint16(c, d)); } } WINRT_EXPORT namespace winrt { struct event_token; struct hstring; struct clock; struct hresult { int32_t value{}; constexpr hresult() noexcept = default; constexpr hresult(int32_t const value) noexcept : value(value) { } constexpr operator int32_t() const noexcept { return value; } }; struct guid { private: template static constexpr guid parse(TStringView value) { // Handle {} and () if (value.size() == 38 && ((value[0] == '{' && value[37] == '}') || (value[0] == '(' && value[37] == ')'))) { value.remove_prefix(1); value.remove_suffix(1); } if (value.size() != 36 || value[8] != '-' || value[13] != '-' || value[18] != '-' || value[23] != '-') { throw std::invalid_argument("value is not a valid GUID string"); } return { impl::uint8_to_uint32 ( impl::hex_to_uint8(value[0], value[1]), impl::hex_to_uint8(value[2], value[3]), impl::hex_to_uint8(value[4], value[5]), impl::hex_to_uint8(value[6], value[7]) ), impl::uint8_to_uint16 ( impl::hex_to_uint8(value[9], value[10]), impl::hex_to_uint8(value[11], value[12]) ), impl::uint8_to_uint16 ( impl::hex_to_uint8(value[14], value[15]), impl::hex_to_uint8(value[16], value[17]) ), { impl::hex_to_uint8(value[19], value[20]), impl::hex_to_uint8(value[21], value[22]), impl::hex_to_uint8(value[24], value[25]), impl::hex_to_uint8(value[26], value[27]), impl::hex_to_uint8(value[28], value[29]), impl::hex_to_uint8(value[30], value[31]), impl::hex_to_uint8(value[32], value[33]), impl::hex_to_uint8(value[34], value[35]), } }; } public: uint32_t Data1; uint16_t Data2; uint16_t Data3; uint8_t Data4[8]; guid() noexcept = default; constexpr guid(uint32_t const Data1, uint16_t const Data2, uint16_t const Data3, std::array const& Data4) noexcept : Data1(Data1), Data2(Data2), Data3(Data3), Data4{ Data4[0], Data4[1], Data4[2], Data4[3], Data4[4], Data4[5], Data4[6], Data4[7] } { } template constexpr guid(GUID const& value) noexcept : guid(convert(value)) { } operator GUID const&() const noexcept { return reinterpret_cast(*this); } constexpr explicit guid(std::string_view const value) : guid(parse(value)) { } constexpr explicit guid(std::wstring_view const value) : guid(parse(value)) { } private: template constexpr static guid convert(T const& value) noexcept { return { value.Data1, value.Data2, value.Data3, { value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] } }; } }; inline bool operator==(guid const& left, guid const& right) noexcept { return !memcmp(&left, &right, sizeof(left)); } inline bool operator!=(guid const& left, guid const& right) noexcept { return !(left == right); } inline bool operator<(guid const& left, guid const& right) noexcept { return memcmp(&left, &right, sizeof(left)) < 0; } } WINRT_EXPORT namespace winrt::Windows::Foundation { enum class TrustLevel : int32_t { BaseTrust, PartialTrust, FullTrust }; struct IUnknown; struct IInspectable; struct IActivationFactory; using TimeSpan = std::chrono::duration; using DateTime = std::chrono::time_point; } namespace winrt::impl { #ifdef WINRT_IMPL_IUNKNOWN_DEFINED using hresult_type = long; using count_type = unsigned long; using guid_type = GUID; #else using hresult_type = int32_t; using count_type = uint32_t; using guid_type = guid; #endif #ifdef __IInspectable_INTERFACE_DEFINED__ using hstring_type = HSTRING; using trust_level_type = ::TrustLevel; #else using hstring_type = void*; using trust_level_type = Windows::Foundation::TrustLevel; #endif inline constexpr hresult error_ok{ 0 }; // S_OK inline constexpr hresult error_fail{ static_cast(0x80004005) }; // E_FAIL inline constexpr hresult error_access_denied{ static_cast(0x80070005) }; // E_ACCESSDENIED inline constexpr hresult error_wrong_thread{ static_cast(0x8001010E) }; // RPC_E_WRONG_THREAD inline constexpr hresult error_not_implemented{ static_cast(0x80004001) }; // E_NOTIMPL inline constexpr hresult error_invalid_argument{ static_cast(0x80070057) }; // E_INVALIDARG inline constexpr hresult error_out_of_bounds{ static_cast(0x8000000B) }; // E_BOUNDS inline constexpr hresult error_no_interface{ static_cast(0x80004002) }; // E_NOINTERFACE inline constexpr hresult error_class_not_available{ static_cast(0x80040111) }; // CLASS_E_CLASSNOTAVAILABLE inline constexpr hresult error_class_not_registered{ static_cast(0x80040154) }; // REGDB_E_CLASSNOTREG inline constexpr hresult error_changed_state{ static_cast(0x8000000C) }; // E_CHANGED_STATE inline constexpr hresult error_illegal_method_call{ static_cast(0x8000000E) }; // E_ILLEGAL_METHOD_CALL inline constexpr hresult error_illegal_state_change{ static_cast(0x8000000D) }; // E_ILLEGAL_STATE_CHANGE inline constexpr hresult error_illegal_delegate_assignment{ static_cast(0x80000018) }; // E_ILLEGAL_DELEGATE_ASSIGNMENT inline constexpr hresult error_canceled{ static_cast(0x800704C7) }; // HRESULT_FROM_WIN32(ERROR_CANCELLED) inline constexpr hresult error_bad_alloc{ static_cast(0x8007000E) }; // E_OUTOFMEMORY inline constexpr hresult error_not_initialized{ static_cast(0x800401F0) }; // CO_E_NOTINITIALIZED inline constexpr hresult error_file_not_found{ static_cast(0x80070002) }; // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) } __declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; __declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; __declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; #if defined(_MSC_VER) #ifdef _M_HYBRID #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count)) #elif _M_ARM64EC #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "=#" #function)) #elif _M_IX86 #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:_WINRT_IMPL_" #function "@" #count "=_" #function "@" #count)) #else #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_IMPL_" #function "=" #function)) #endif #elif defined(__GNUC__) #if defined(__i386__) #define WINRT_IMPL_LINK(function, count) __asm__("_" #function "@" #count) #else #define WINRT_IMPL_LINK(function, count) __asm__(#function) #endif #endif extern "C" { int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept WINRT_IMPL_LINK(RoGetActivationFactory, 12); int32_t __stdcall WINRT_IMPL_RoGetAgileReference(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept WINRT_IMPL_LINK(RoGetAgileReference, 16); int32_t __stdcall WINRT_IMPL_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept WINRT_IMPL_LINK(SetThreadpoolTimerEx, 16); int32_t __stdcall WINRT_IMPL_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept WINRT_IMPL_LINK(SetThreadpoolWaitEx, 16); int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(int32_t error, void* message, void* exception) noexcept WINRT_IMPL_LINK(RoOriginateLanguageException, 12); int32_t __stdcall WINRT_IMPL_RoCaptureErrorContext(int32_t error) noexcept WINRT_IMPL_LINK(RoCaptureErrorContext, 4); void __stdcall WINRT_IMPL_RoFailFastWithErrorContext(int32_t) noexcept WINRT_IMPL_LINK(RoFailFastWithErrorContext, 4); int32_t __stdcall WINRT_IMPL_RoTransformError(int32_t, int32_t, void*) noexcept WINRT_IMPL_LINK(RoTransformError, 12); void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, uint32_t flags) noexcept WINRT_IMPL_LINK(LoadLibraryExW, 12); int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept WINRT_IMPL_LINK(FreeLibrary, 4); void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept WINRT_IMPL_LINK(GetProcAddress, 8); int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept WINRT_IMPL_LINK(SetErrorInfo, 8); int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept WINRT_IMPL_LINK(GetErrorInfo, 8); int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, uint32_t type) noexcept WINRT_IMPL_LINK(CoInitializeEx, 8); void __stdcall WINRT_IMPL_CoUninitialize() noexcept WINRT_IMPL_LINK(CoUninitialize, 0); int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8); int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoCreateInstance, 20); int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetCallContext, 8); int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetObjectContext, 8); int32_t __stdcall WINRT_IMPL_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept WINRT_IMPL_LINK(CoGetApartmentType, 8); void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept WINRT_IMPL_LINK(CoTaskMemAlloc, 4); void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept WINRT_IMPL_LINK(CoTaskMemFree, 4); winrt::impl::bstr __stdcall WINRT_IMPL_SysAllocString(wchar_t const* value) noexcept WINRT_IMPL_LINK(SysAllocString, 4); void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysFreeString, 4); uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysStringLen, 4); int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept WINRT_IMPL_LINK(IIDFromString, 8); int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size) noexcept WINRT_IMPL_LINK(MultiByteToWideChar, 24); int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(uint32_t codepage, uint32_t flags, wchar_t const* int_string, int32_t in_size, char* out_string, int32_t out_size, char const* default_char, int32_t* default_used) noexcept WINRT_IMPL_LINK(WideCharToMultiByte, 32); void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, uint32_t flags, size_t bytes) noexcept WINRT_IMPL_LINK(HeapAlloc, 12); int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, uint32_t flags, void* value) noexcept WINRT_IMPL_LINK(HeapFree, 12); void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept WINRT_IMPL_LINK(GetProcessHeap, 0); uint32_t __stdcall WINRT_IMPL_FormatMessageW(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments) noexcept WINRT_IMPL_LINK(FormatMessageW, 28); uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept WINRT_IMPL_LINK(GetLastError, 0); void __stdcall WINRT_IMPL_GetSystemTimePreciseAsFileTime(void* result) noexcept WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4); uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, uintptr_t length) noexcept WINRT_IMPL_LINK(VirtualQuery, 12); void* __stdcall WINRT_IMPL_EncodePointer(void* ptr) noexcept WINRT_IMPL_LINK(EncodePointer, 4); int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, uint32_t access, void** token) noexcept WINRT_IMPL_LINK(OpenProcessToken, 12); void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept WINRT_IMPL_LINK(GetCurrentProcess, 0); int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept WINRT_IMPL_LINK(DuplicateToken, 12); int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept WINRT_IMPL_LINK(OpenThreadToken, 16); void* __stdcall WINRT_IMPL_GetCurrentThread() noexcept WINRT_IMPL_LINK(GetCurrentThread, 0); int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept WINRT_IMPL_LINK(SetThreadToken, 8); void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4); void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockShared, 4); uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4); uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4); void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4); void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockShared, 4); int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags) noexcept WINRT_IMPL_LINK(SleepConditionVariableSRW, 16); void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeConditionVariable, 4); void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeAllConditionVariable, 4); void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept WINRT_IMPL_LINK(InterlockedPushEntrySList, 8); void* __stdcall WINRT_IMPL_InterlockedFlushSList(void* head) noexcept WINRT_IMPL_LINK(InterlockedFlushSList, 4); void* __stdcall WINRT_IMPL_CreateEventW(void*, int32_t, int32_t, void*) noexcept WINRT_IMPL_LINK(CreateEventW, 16); int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept WINRT_IMPL_LINK(SetEvent, 4); int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept WINRT_IMPL_LINK(CloseHandle, 4); uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept WINRT_IMPL_LINK(WaitForSingleObject, 8); int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12); winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolTimer, 12); void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept WINRT_IMPL_LINK(SetThreadpoolTimer, 16); void __stdcall WINRT_IMPL_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept WINRT_IMPL_LINK(CloseThreadpoolTimer, 4); winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolWait, 12); void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept WINRT_IMPL_LINK(SetThreadpoolWait, 12); void __stdcall WINRT_IMPL_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept WINRT_IMPL_LINK(CloseThreadpoolWait, 4); winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolIo, 16); void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(StartThreadpoolIo, 4); void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CancelThreadpoolIo, 4); void __stdcall WINRT_IMPL_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CloseThreadpoolIo, 4); winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept WINRT_IMPL_LINK(CreateThreadpool, 4); void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8); int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8); void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept WINRT_IMPL_LINK(CloseThreadpool, 4); int32_t __stdcall WINRT_CanUnloadNow() noexcept; int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; } #undef WINRT_IMPL_LINK WINRT_EXPORT namespace winrt { hresult check_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()); hresult to_hresult() noexcept; template D* get_self(I const& from) noexcept; struct take_ownership_from_abi_t {}; inline constexpr take_ownership_from_abi_t take_ownership_from_abi{}; template struct com_ptr; template D* get_self(com_ptr const& from) noexcept; namespace param { template struct iterable; template struct async_iterable; template struct map_view; template struct async_map_view; template struct map; template struct vector_view; template struct async_vector_view; template struct vector; } } namespace winrt::impl { using namespace std::literals; template struct reference_traits; template struct identity { using type = T; }; template struct abi { using type = T; }; template struct abi>> { using type = std::underlying_type_t; }; template using abi_t = typename abi::type; template struct consume; template using consume_t = typename consume::template type; template struct delegate; template > struct default_interface { using type = T; }; struct basic_category; struct interface_category; struct delegate_category; struct enum_category; struct class_category; template struct category { using type = void; }; template using category_t = typename category::type; template inline constexpr bool has_category_v = !std::is_same_v, void>; template struct generic_category; template struct struct_category; template struct category_signature; template struct signature { static constexpr auto data{ category_signature, T>::data }; }; template struct classic_com_guid_error { #if !defined(__MINGW32__) && defined(__clang__) && !WINRT_IMPL_HAS_DECLSPEC_UUID static_assert(std::is_void_v /* dependent_false */, "To use classic COM interfaces, you must compile with -fms-extensions."); #elif !defined(WINRT_IMPL_IUNKNOWN_DEFINED) static_assert(std::is_void_v /* dependent_false */, "To use classic COM interfaces, you must include before including C++/WinRT headers."); #else // MSVC won't hit this struct, so we can safely assume everything that isn't Clang isn't supported static_assert(std::is_void_v /* dependent_false */, "Classic COM interfaces are not supported with this compiler."); #endif }; template #if (defined(_MSC_VER) && !defined(__clang__)) || ((WINRT_IMPL_HAS_DECLSPEC_UUID || defined(__MINGW32__)) && defined(WINRT_IMPL_IUNKNOWN_DEFINED)) inline constexpr guid guid_v{ __uuidof(T) }; #else inline constexpr guid guid_v = classic_com_guid_error::value; #endif template constexpr auto to_underlying_type(T const value) noexcept { return static_cast>(value); } template > struct is_implements : std::false_type {}; template struct is_implements> : std::true_type {}; template inline constexpr bool is_implements_v = is_implements::value; template struct require_one : consume_t { operator I() const noexcept { return static_cast(this)->template try_as(); } }; template struct WINRT_IMPL_EMPTY_BASES require : require_one... {}; template struct base_one { operator I() const noexcept { return static_cast(this)->template try_as(); } }; template struct WINRT_IMPL_EMPTY_BASES base : base_one... {}; template T empty_value() noexcept { if constexpr (std::is_base_of_v) { return nullptr; } else { return {}; } } template struct movable_primitive { T value = empty_value; movable_primitive() = default; movable_primitive(T const& init) : value(init) {} movable_primitive(movable_primitive const&) = default; movable_primitive(movable_primitive&& other) : value(other.detach()) {} movable_primitive& operator=(movable_primitive const&) = default; movable_primitive& operator=(movable_primitive&& other) { value = other.detach(); return *this; } T detach() { return std::exchange(value, empty_value); } }; template struct arg { using in = abi_t; }; template struct arg>> { using in = void*; }; template using arg_in = typename arg::in; template using arg_out = arg_in*; template struct produce_base; template struct produce; template struct produce : produce_base { }; template struct wrapped_type { using type = T; }; template struct wrapped_type> { using type = T; }; template using wrapped_type_t = typename wrapped_type::type; template struct typelist {}; template struct typelist_concat; template <> struct typelist_concat<> { using type = winrt::impl::typelist<>; }; template struct typelist_concat> { using type = winrt::impl::typelist; }; template struct typelist_concat, winrt::impl::typelist, Rest...> : typelist_concat, Rest...> {}; template struct for_each; template struct for_each> { template static auto apply([[maybe_unused]] Func&& func) { return (func(Types{}), ...); } }; template struct find_if; template struct find_if> { template static bool apply([[maybe_unused]] Func&& func) { return (func(Types{}) || ...); } }; } WINRT_EXPORT namespace winrt { template using default_interface = typename impl::default_interface::type; template constexpr guid const& guid_of() noexcept { return impl::guid_v>; } template bool is_guid_of(guid const& id) noexcept { return ((id == guid_of()) || ...); } } namespace winrt::impl { template constexpr std::array to_array(T const* value, std::index_sequence const) noexcept { return { value[Index]... }; } template constexpr auto to_array(std::array const& value) noexcept { return value; } template constexpr auto to_array(char const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } template constexpr auto to_array(wchar_t const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } template constexpr std::array concat( [[maybe_unused]] std::array const& left, [[maybe_unused]] std::array const& right, std::index_sequence const, std::index_sequence const) noexcept { return { left[LeftIndex]..., right[RightIndex]... }; } template constexpr auto concat(std::array const& left, std::array const& right) noexcept { return concat(left, right, std::make_index_sequence(), std::make_index_sequence()); } template constexpr auto concat(std::array const& left, T const(&right)[RightSize]) noexcept { return concat(left, to_array(right)); } template constexpr auto concat(T const(&left)[LeftSize], std::array const& right) noexcept { return concat(to_array(left), right); } template constexpr auto concat(std::array const& left, T const right) noexcept { return concat(left, std::array{right}); } template constexpr auto concat(T const left, std::array const& right) noexcept { return concat(std::array{left}, right); } template constexpr auto combine(First const& first, Rest const&... rest) noexcept { if constexpr (sizeof...(rest) == 0) { return to_array(first); } else { return concat(first, combine(rest...)); } } template constexpr std::array zconcat_base(std::array const& left, std::array const& right, std::index_sequence const, std::index_sequence const) noexcept { return { left[LI]..., right[RI]..., T{} }; } template constexpr auto zconcat(std::array const& left, std::array const& right) noexcept { return zconcat_base(left, right, std::make_index_sequence(), std::make_index_sequence()); } template constexpr std::array to_zarray_base(T const(&value)[S], std::index_sequence const) noexcept { return { value[I]... }; } template constexpr auto to_zarray(T const(&value)[S]) noexcept { return to_zarray_base(value, std::make_index_sequence()); } template constexpr auto to_zarray(std::array const& value) noexcept { return value; } template constexpr auto zcombine(First const& first, Rest const&... rest) noexcept { if constexpr (sizeof...(rest) == 0) { return to_zarray(first); } else { return zconcat(to_zarray(first), zcombine(rest...)); } } constexpr std::array to_array(uint32_t value) noexcept { return { static_cast(value & 0x000000ff), static_cast((value & 0x0000ff00) >> 8), static_cast((value & 0x00ff0000) >> 16), static_cast((value & 0xff000000) >> 24) }; } constexpr std::array to_array(uint16_t value) noexcept { return { static_cast(value & 0x00ff), static_cast((value & 0xff00) >> 8) }; } constexpr auto to_array(guid const& value) noexcept { return combine(to_array(value.Data1), to_array(value.Data2), to_array(value.Data3), std::array{ value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] }); } template constexpr T to_hex_digit(uint8_t value) noexcept { value &= 0xF; return value < 10 ? static_cast('0') + value : static_cast('a') + (value - 10); } template constexpr std::array uint8_to_hex(uint8_t const value) noexcept { return { to_hex_digit(value >> 4), to_hex_digit(value & 0xF) }; } template constexpr auto uint16_to_hex(uint16_t value) noexcept { return combine(uint8_to_hex(static_cast(value >> 8)), uint8_to_hex(value & 0xFF)); } template constexpr auto uint32_to_hex(uint32_t const value) noexcept { return combine(uint16_to_hex(value >> 16), uint16_to_hex(value & 0xFFFF)); } template constexpr auto to_array(guid const& value) noexcept { return combine ( std::array{'{'}, uint32_to_hex(value.Data1), std::array{'-'}, uint16_to_hex(value.Data2), std::array{'-'}, uint16_to_hex(value.Data3), std::array{'-'}, uint16_to_hex(value.Data4[0] << 8 | value.Data4[1]), std::array{'-'}, uint16_to_hex(value.Data4[2] << 8 | value.Data4[3]), uint16_to_hex(value.Data4[4] << 8 | value.Data4[5]), uint16_to_hex(value.Data4[6] << 8 | value.Data4[7]), std::array{'}'} ); } constexpr uint32_t to_guid(uint8_t a, uint8_t b, uint8_t c, uint8_t d) noexcept { return (static_cast(d) << 24) | (static_cast(c) << 16) | (static_cast(b) << 8) | static_cast(a); } constexpr uint16_t to_guid(uint8_t a, uint8_t b) noexcept { return (static_cast(b) << 8) | static_cast(a); } template constexpr guid to_guid(std::array const& arr) noexcept { return { to_guid(arr[0], arr[1], arr[2], arr[3]), to_guid(arr[4], arr[5]), to_guid(arr[6], arr[7]), { arr[8], arr[9], arr[10], arr[11], arr[12], arr[13], arr[14], arr[15] } }; } constexpr uint32_t endian_swap(uint32_t value) noexcept { return (value & 0xFF000000) >> 24 | (value & 0x00FF0000) >> 8 | (value & 0x0000FF00) << 8 | (value & 0x000000FF) << 24; } constexpr uint16_t endian_swap(uint16_t value) noexcept { return (value & 0xFF00) >> 8 | (value & 0x00FF) << 8; } constexpr guid endian_swap(guid value) noexcept { value.Data1 = endian_swap(value.Data1); value.Data2 = endian_swap(value.Data2); value.Data3 = endian_swap(value.Data3); return value; } constexpr guid set_named_guid_fields(guid value) noexcept { value.Data3 = static_cast((value.Data3 & 0x0fff) | (5 << 12)); value.Data4[0] = static_cast((value.Data4[0] & 0x3f) | 0x80); return value; } template constexpr std::array char_to_byte_array(std::array const& value, std::index_sequence const) noexcept { return { static_cast(value[Index])... }; } constexpr auto sha1_rotl(uint8_t bits, uint32_t word) noexcept { return (word << bits) | (word >> (32 - bits)); } constexpr auto sha_ch(uint32_t x, uint32_t y, uint32_t z) noexcept { return (x & y) ^ ((~x) & z); } constexpr auto sha_parity(uint32_t x, uint32_t y, uint32_t z) noexcept { return x ^ y ^ z; } constexpr auto sha_maj(uint32_t x, uint32_t y, uint32_t z) noexcept { return (x & y) ^ (x & z) ^ (y & z); } constexpr std::array process_msg_block(uint8_t const* input, size_t start_pos, std::array const& intermediate_hash) noexcept { uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; std::array W = {}; size_t t = 0; uint32_t temp = 0; for (t = 0; t < 16; t++) { W[t] = static_cast(input[start_pos + t * 4]) << 24; W[t] = W[t] | static_cast(input[start_pos + t * 4 + 1]) << 16; W[t] = W[t] | static_cast(input[start_pos + t * 4 + 2]) << 8; W[t] = W[t] | static_cast(input[start_pos + t * 4 + 3]); } for (t = 16; t < 80; t++) { W[t] = sha1_rotl(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); } uint32_t A = intermediate_hash[0]; uint32_t B = intermediate_hash[1]; uint32_t C = intermediate_hash[2]; uint32_t D = intermediate_hash[3]; uint32_t E = intermediate_hash[4]; for (t = 0; t < 20; t++) { temp = sha1_rotl(5, A) + sha_ch(B, C, D) + E + W[t] + K[0]; E = D; D = C; C = sha1_rotl(30, B); B = A; A = temp; } for (t = 20; t < 40; t++) { temp = sha1_rotl(5, A) + sha_parity(B, C, D) + E + W[t] + K[1]; E = D; D = C; C = sha1_rotl(30, B); B = A; A = temp; } for (t = 40; t < 60; t++) { temp = sha1_rotl(5, A) + sha_maj(B, C, D) + E + W[t] + K[2]; E = D; D = C; C = sha1_rotl(30, B); B = A; A = temp; } for (t = 60; t < 80; t++) { temp = sha1_rotl(5, A) + sha_parity(B, C, D) + E + W[t] + K[3]; E = D; D = C; C = sha1_rotl(30, B); B = A; A = temp; } return { intermediate_hash[0] + A, intermediate_hash[1] + B, intermediate_hash[2] + C, intermediate_hash[3] + D, intermediate_hash[4] + E }; } template constexpr std::array process_msg_block(std::array const& input, size_t start_pos, std::array const& intermediate_hash) noexcept { return process_msg_block(input.data(), start_pos, intermediate_hash); } constexpr std::array size_to_bytes(size_t size) noexcept { return { static_cast((size & 0xff00000000000000) >> 56), static_cast((size & 0x00ff000000000000) >> 48), static_cast((size & 0x0000ff0000000000) >> 40), static_cast((size & 0x000000ff00000000) >> 32), static_cast((size & 0x00000000ff000000) >> 24), static_cast((size & 0x0000000000ff0000) >> 16), static_cast((size & 0x000000000000ff00) >> 8), static_cast((size & 0x00000000000000ff) >> 0) }; } template constexpr std::array make_remaining([[maybe_unused]] std::array const& input, [[maybe_unused]] size_t start_pos, std::index_sequence) noexcept { return { input[Index + start_pos]..., 0x80 }; } template constexpr auto make_remaining(std::array const& input, size_t start_pos) noexcept { constexpr auto remaining_size = Size % 64; return make_remaining(input, start_pos, std::make_index_sequence()); } template constexpr auto make_buffer(std::array const& remaining_buffer) noexcept { constexpr auto message_length = (RemainderSize + 8 <= 64) ? 64 : 64 * 2; constexpr auto padding_length = message_length - RemainderSize - 8; auto padding_buffer = std::array{}; auto length_buffer = size_to_bytes(InputSize * 8); return combine(remaining_buffer, padding_buffer, length_buffer); } template constexpr std::array finalize_remaining_buffer(std::array const& input, std::array const& intermediate_hash) noexcept { if constexpr (Size == 64) { return process_msg_block(input, 0, intermediate_hash); } else if constexpr (Size == 64 * 2) { return process_msg_block(input, 64, process_msg_block(input, 0, intermediate_hash)); } } template constexpr std::array get_result(std::array const& intermediate_hash, std::index_sequence) noexcept { return { static_cast(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... }; } constexpr auto get_result(std::array const& intermediate_hash) noexcept { return get_result(intermediate_hash, std::make_index_sequence<20>{}); } template constexpr auto calculate_sha1(std::array const& input) noexcept { std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; size_t i = 0; while (i + 64 <= Size) { intermediate_hash = process_msg_block(input, i, intermediate_hash); i += 64; } intermediate_hash = finalize_remaining_buffer(make_buffer(make_remaining(input, i)), intermediate_hash); return get_result(intermediate_hash); } template constexpr guid generate_guid(std::array const& value) noexcept { guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } }; auto buffer = combine(to_array(namespace_guid), char_to_byte_array(value, std::make_index_sequence())); auto hash = calculate_sha1(buffer); auto big_endian_guid = to_guid(hash); auto little_endian_guid = endian_swap(big_endian_guid); return set_named_guid_fields(little_endian_guid); } template struct arg_collection { constexpr static auto data{ combine(to_array(signature::data), ";", arg_collection::data) }; }; template struct arg_collection { constexpr static auto data{ to_array(signature::data) }; }; template struct pinterface_guid { #ifdef _MSC_VER #pragma warning(suppress: 4307) #endif static constexpr guid value{ generate_guid(signature::data) }; }; template #ifdef _MSC_VER #pragma warning(suppress: 4307) #endif inline constexpr auto name_v { combine ( to_array(guid_of()), std::array{ L'\0' } ) }; constexpr size_t to_utf8_size(wchar_t const value) noexcept { if (value <= 0x7F) { return 1; } if (value <= 0x7FF) { return 2; } return 3; } constexpr size_t to_utf8(wchar_t const value, char* buffer) noexcept { if (value <= 0x7F) { *buffer = static_cast(value); return 1; } if (value <= 0x7FF) { *buffer = static_cast(0xC0 | (value >> 6)); *(buffer + 1) = 0x80 | (value & 0x3F); return 2; } *buffer = 0xE0 | (value >> 12); *(buffer + 1) = 0x80 | ((value >> 6) & 0x3F); *(buffer + 2) = 0x80 | (value & 0x3F); return 3; } template constexpr size_t to_utf8_size() noexcept { auto input = to_array(name_v); size_t length = 0; for (wchar_t const element : input) { length += to_utf8_size(element); } return length; } template constexpr auto to_utf8() noexcept { auto input = to_array(name_v); std::array()> output{}; size_t offset{}; for (wchar_t const element : input) { offset += to_utf8(element, &output[offset]); } return output; } template constexpr guid generic_guid_v{}; template constexpr auto& basic_signature_v = ""; template <> inline constexpr auto& basic_signature_v = "b1"; template <> inline constexpr auto& basic_signature_v = "i1"; template <> inline constexpr auto& basic_signature_v = "i2"; template <> inline constexpr auto& basic_signature_v = "i4"; template <> inline constexpr auto& basic_signature_v = "i8"; template <> inline constexpr auto& basic_signature_v = "u1"; template <> inline constexpr auto& basic_signature_v = "u2"; template <> inline constexpr auto& basic_signature_v = "u4"; template <> inline constexpr auto& basic_signature_v = "u8"; template <> inline constexpr auto& basic_signature_v = "f4"; template <> inline constexpr auto& basic_signature_v = "f8"; template <> inline constexpr auto& basic_signature_v = "c2"; template <> inline constexpr auto& basic_signature_v = "g16"; template <> inline constexpr auto& basic_signature_v = "string"; template <> inline constexpr auto& basic_signature_v = "cinterface(IInspectable)"; template <> inline constexpr auto& name_v = L"Boolean"; template <> inline constexpr auto& name_v = L"Int8"; template <> inline constexpr auto& name_v = L"Int16"; template <> inline constexpr auto& name_v = L"Int32"; template <> inline constexpr auto& name_v = L"Int64"; template <> inline constexpr auto& name_v = L"UInt8"; template <> inline constexpr auto& name_v = L"UInt16"; template <> inline constexpr auto& name_v = L"UInt32"; template <> inline constexpr auto& name_v = L"UInt64"; template <> inline constexpr auto& name_v = L"Single"; template <> inline constexpr auto& name_v = L"Double"; template <> inline constexpr auto& name_v = L"Char16"; template <> inline constexpr auto& name_v = L"Guid"; template <> inline constexpr auto& name_v = L"String"; template <> inline constexpr auto& name_v = L"Windows.Foundation.HResult"; template <> inline constexpr auto& name_v = L"Windows.Foundation.EventRegistrationToken"; template <> inline constexpr auto& name_v = L"Object"; template <> inline constexpr auto& name_v = L"Windows.Foundation.TimeSpan"; template <> inline constexpr auto& name_v = L"Windows.Foundation.DateTime"; template <> inline constexpr auto& name_v = L"IAgileObject"; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = struct_category; }; template <> struct category { using type = struct_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = struct_category; }; template <> struct category { using type = struct_category; }; template struct category_signature { constexpr static auto data{ to_array(basic_signature_v) }; }; template struct category_signature { using enum_type = std::underlying_type_t; constexpr static auto data{ combine("enum(", to_utf8(), ";", signature::data, ")") }; }; template struct category_signature, T> { constexpr static auto data{ combine("struct(", to_utf8(), ";", arg_collection::data, ")") }; }; template struct category_signature { constexpr static auto data{ combine("rc(", to_utf8(), ";", signature>::data, ")") }; }; template struct category_signature, T> { constexpr static auto data{ combine("pinterface(", to_array(generic_guid_v), ";", arg_collection::data, ")") }; }; template struct category_signature { constexpr static auto data{ to_array(guid_of()) }; }; template struct category_signature { constexpr static auto data{ combine("delegate(", to_array(guid_of()), ")") }; }; template constexpr std::wstring_view to_wstring_view(std::array const& value) noexcept { return { value.data(), Size - 1 }; } template constexpr std::wstring_view to_wstring_view(wchar_t const (&value)[Size]) noexcept { return { value, Size - 1 }; } } WINRT_EXPORT namespace winrt { template constexpr auto name_of() noexcept { return impl::to_wstring_view(impl::name_v); } } WINRT_EXPORT namespace winrt { template struct handle_type { using type = typename T::type; handle_type() noexcept = default; explicit handle_type(type value) noexcept : m_value(value) { } handle_type(handle_type&& other) noexcept : m_value(other.detach()) { } handle_type& operator=(handle_type&& other) noexcept { if (this != &other) { attach(other.detach()); } return*this; } ~handle_type() noexcept { close(); } void close() noexcept { if (*this) { T::close(m_value); m_value = T::invalid(); } } explicit operator bool() const noexcept { return T::invalid() != m_value; } type get() const noexcept { return m_value; } type* put() noexcept { close(); return &m_value; } void attach(type value) noexcept { close(); *put() = value; } type detach() noexcept { type value = m_value; m_value = T::invalid(); return value; } friend void swap(handle_type& left, handle_type& right) noexcept { std::swap(left.m_value, right.m_value); } private: type m_value = T::invalid(); }; struct handle_traits { using type = void*; static void close(type value) noexcept { WINRT_VERIFY_(1, WINRT_IMPL_CloseHandle(value)); } static constexpr type invalid() noexcept { return nullptr; } }; using handle = handle_type; struct file_handle_traits { using type = void*; static void close(type value) noexcept { WINRT_VERIFY_(1, WINRT_IMPL_CloseHandle(value)); } static type invalid() noexcept { return reinterpret_cast(-1); } }; using file_handle = handle_type; } WINRT_EXPORT namespace winrt { struct slim_condition_variable; struct slim_mutex { slim_mutex(slim_mutex const&) = delete; slim_mutex& operator=(slim_mutex const&) = delete; slim_mutex() noexcept = default; void lock() noexcept { WINRT_IMPL_AcquireSRWLockExclusive(&m_lock); } void lock_shared() noexcept { WINRT_IMPL_AcquireSRWLockShared(&m_lock); } bool try_lock() noexcept { return 0 != WINRT_IMPL_TryAcquireSRWLockExclusive(&m_lock); } bool try_lock_shared() noexcept { return 0 != WINRT_IMPL_TryAcquireSRWLockShared(&m_lock); } void unlock() noexcept { WINRT_IMPL_ReleaseSRWLockExclusive(&m_lock); } void unlock_shared() noexcept { WINRT_IMPL_ReleaseSRWLockShared(&m_lock); } private: friend slim_condition_variable; auto get() noexcept { return &m_lock; } impl::srwlock m_lock{}; }; struct slim_lock_guard { explicit slim_lock_guard(slim_mutex& m) noexcept : m_mutex(m) { m_mutex.lock(); } slim_lock_guard(slim_lock_guard const&) = delete; ~slim_lock_guard() noexcept { m_mutex.unlock(); } private: slim_mutex& m_mutex; }; struct slim_shared_lock_guard { explicit slim_shared_lock_guard(slim_mutex& m) noexcept : m_mutex(m) { m_mutex.lock_shared(); } slim_shared_lock_guard(slim_shared_lock_guard const&) = delete; ~slim_shared_lock_guard() noexcept { m_mutex.unlock_shared(); } private: slim_mutex& m_mutex; }; struct slim_condition_variable { slim_condition_variable(slim_condition_variable const&) = delete; slim_condition_variable const& operator=(slim_condition_variable const&) = delete; slim_condition_variable() noexcept = default; template void wait(slim_mutex& x, T predicate) { while (!predicate()) { WINRT_VERIFY(WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), 0xFFFFFFFF /*INFINITE*/, 0)); } } template bool wait_for(slim_mutex& x, std::chrono::high_resolution_clock::duration const timeout, T predicate) { auto const until = std::chrono::high_resolution_clock::now() + timeout; while (!predicate()) { auto const milliseconds = std::chrono::duration_cast(until - std::chrono::high_resolution_clock::now()).count(); if (milliseconds <= 0) { return false; } if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast(milliseconds), 0)) { return predicate(); } } return true; } void notify_one() noexcept { WINRT_IMPL_WakeConditionVariable(&m_cv); } void notify_all() noexcept { WINRT_IMPL_WakeAllConditionVariable(&m_cv); } private: impl::condition_variable m_cv{}; }; } namespace winrt::impl { template <> struct abi { struct WINRT_IMPL_NOVTABLE type { virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; virtual uint32_t __stdcall AddRef() noexcept = 0; virtual uint32_t __stdcall Release() noexcept = 0; }; }; using unknown_abi = abi_t; template <> struct abi { struct WINRT_IMPL_NOVTABLE type : unknown_abi { virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; virtual int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* level) noexcept = 0; }; }; using inspectable_abi = abi_t; template <> struct abi { struct WINRT_IMPL_NOVTABLE type : inspectable_abi { virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; }; }; struct WINRT_IMPL_NOVTABLE IAgileObject : unknown_abi {}; struct WINRT_IMPL_NOVTABLE IAgileReference : unknown_abi { virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IMarshal : unknown_abi { virtual int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept = 0; virtual int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept = 0; virtual int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept = 0; virtual int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept = 0; virtual int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept = 0; virtual int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IGlobalInterfaceTable : unknown_abi { virtual int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, uint32_t* cookie) noexcept = 0; virtual int32_t __stdcall RevokeInterfaceFromGlobal(uint32_t cookie) noexcept = 0; virtual int32_t __stdcall GetInterfaceFromGlobal(uint32_t cookie, guid const& iid, void** object) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IStaticLifetime : inspectable_abi { virtual int32_t __stdcall unused() noexcept = 0; virtual int32_t __stdcall GetCollection(void** value) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IStaticLifetimeCollection : inspectable_abi { virtual int32_t __stdcall Lookup(void*, void**) noexcept = 0; virtual int32_t __stdcall unused() noexcept = 0; virtual int32_t __stdcall unused2() noexcept = 0; virtual int32_t __stdcall unused3() noexcept = 0; virtual int32_t __stdcall Insert(void*, void*, bool*) noexcept = 0; virtual int32_t __stdcall Remove(void*) noexcept = 0; virtual int32_t __stdcall unused4() noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IWeakReference : unknown_abi { virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IWeakReferenceSource : unknown_abi { virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IRestrictedErrorInfo : unknown_abi { virtual int32_t __stdcall GetErrorDetails(bstr* description, int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; virtual int32_t __stdcall GetReference(bstr* reference) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IErrorInfo : unknown_abi { virtual int32_t __stdcall GetGUID(guid* value) noexcept = 0; virtual int32_t __stdcall GetSource(bstr* value) noexcept = 0; virtual int32_t __stdcall GetDescription(bstr* value) noexcept = 0; virtual int32_t __stdcall GetHelpFile(bstr* value) noexcept = 0; virtual int32_t __stdcall GetHelpContext(uint32_t* value) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE ILanguageExceptionErrorInfo2 : unknown_abi { virtual int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; virtual int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; virtual int32_t __stdcall CapturePropagationContext(void* exception) noexcept = 0; virtual int32_t __stdcall GetPropagationContextHead(ILanguageExceptionErrorInfo2** head) noexcept = 0; }; struct ICallbackWithNoReentrancyToApplicationSTA; struct WINRT_IMPL_NOVTABLE IContextCallback : unknown_abi { virtual int32_t __stdcall ContextCallback(int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IServerSecurity : unknown_abi { virtual int32_t __stdcall QueryBlanket(uint32_t*, uint32_t*, wchar_t**, uint32_t*, uint32_t*, void**, uint32_t*) noexcept = 0; virtual int32_t __stdcall ImpersonateClient() noexcept = 0; virtual int32_t __stdcall RevertToSelf() noexcept = 0; virtual int32_t __stdcall IsImpersonating() noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IBufferByteAccess : unknown_abi { virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0; }; struct WINRT_IMPL_NOVTABLE IMemoryBufferByteAccess : unknown_abi { virtual int32_t __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) noexcept = 0; }; template <> struct abi { using type = int64_t; }; template <> struct abi { using type = int64_t; }; template <> inline constexpr guid guid_v{ 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0xAF86E2E0, 0xB12D, 0x4C6A, { 0x9C,0x5A,0xD7,0xAA,0x65,0x10,0x1E,0x90 } }; template <> inline constexpr guid guid_v{ 0x00000035, 0x0000, 0x0000, { 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x94EA2B94, 0xE9CC, 0x49E0, { 0xC0,0xFF,0xEE,0x64,0xCA,0x8F,0x5B,0x90 } }; template <> inline constexpr guid guid_v{ 0xC03F6A43, 0x65A4, 0x9818, { 0x98,0x7E,0xE0,0xB8,0x10,0xD2,0xA6,0xF2 } }; template <> inline constexpr guid guid_v{ 0x00000003, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x00000146, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x17b0e613, 0x942a, 0x422d, { 0x90,0x4c,0xf9,0x0d,0xc7,0x1a,0x7d,0xae } }; template <> inline constexpr guid guid_v{ 0x1b0d3570, 0x0877, 0x5ec2, { 0x8a,0x2c,0x3b,0x95,0x39,0x50,0x6a,0xca } }; template <> inline constexpr guid guid_v{ 0x00000037, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x00000038, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x82BA7092, 0x4C88, 0x427D, { 0xA7,0xBC,0x16,0xDD,0x93,0xFE,0xB6,0x7E } }; template <> inline constexpr guid guid_v{ 0x1CF2B120, 0x547D, 0x101B, { 0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19 } }; template <> inline constexpr guid guid_v{ 0x5746E5C4, 0x5B97, 0x424C, { 0xB6,0x20,0x28,0x22,0x91,0x57,0x34,0xDD } }; template <> inline constexpr guid guid_v{ 0x0A299774, 0x3E4E, 0xFC42, { 0x1D,0x9D,0x72,0xCE,0xE1,0x05,0xCA,0x57 } }; template <> inline constexpr guid guid_v{ 0x000001da, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x0000013E, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; template <> inline constexpr guid guid_v{ 0x905a0fef, 0xbc53, 0x11df, { 0x8c,0x49,0x00,0x1e,0x4f,0xc6,0x86,0xda } }; template <> inline constexpr guid guid_v{ 0x5b0d3235, 0x4dba, 0x4d44, { 0x86,0x5e,0x8f,0x1d,0x0e,0x4f,0xd0,0x4d } }; } namespace winrt::impl { #ifdef WINRT_DIAGNOSTICS struct factory_diagnostics_info { bool is_agile{ true }; uint32_t requests{ 0 }; }; struct diagnostics_info { std::map queries; std::map factories; }; struct diagnostics_cache { template void add_query() { slim_lock_guard const guard(m_lock); ++m_info.queries[name_of()]; } template void add_factory() { slim_lock_guard const guard(m_lock); factory_diagnostics_info& factory = m_info.factories[name_of()]; ++factory.requests; } template void non_agile_factory() { slim_lock_guard const guard(m_lock); factory_diagnostics_info& factory = m_info.factories[name_of()]; factory.is_agile = false; } auto get() { slim_lock_guard const guard(m_lock); return m_info; } auto detach() { slim_lock_guard const guard(m_lock); return std::move(m_info); } private: slim_mutex m_lock; diagnostics_info m_info; }; inline diagnostics_cache& get_diagnostics_info() noexcept { static diagnostics_cache info; return info; } #endif template using com_ref = std::conditional_t, T, com_ptr>; template , int> = 0> com_ref wrap_as_result(void* result) { return { &static_cast::type>*>(result)->shim(), take_ownership_from_abi }; } template , int> = 0> com_ref wrap_as_result(void* result) { return { result, take_ownership_from_abi }; } template struct is_classic_com_interface : std::conjunction, std::negation>> {}; template struct is_com_interface : std::disjunction, std::is_base_of, is_implements, is_classic_com_interface> {}; template inline constexpr bool is_com_interface_v = is_com_interface::value; // You must include to use this overload. template , int> = 0> auto as(From* ptr); template , int> = 0> com_ref as(From* ptr) { #ifdef WINRT_DIAGNOSTICS get_diagnostics_info().add_query(); #endif if (!ptr) { return nullptr; } void* result{}; check_hresult(ptr->QueryInterface(guid_of(), &result)); return wrap_as_result(result); } // You must include to use this overload. template , int> = 0> auto try_as(From* ptr) noexcept; template , int> = 0> com_ref try_as(From* ptr) noexcept { #ifdef WINRT_DIAGNOSTICS get_diagnostics_info().add_query(); #endif if (!ptr) { return nullptr; } void* result{}; ptr->QueryInterface(guid_of(), &result); return wrap_as_result(result); } template , int> = 0> com_ref try_as_with_reason(From* ptr, hresult& code) noexcept { #ifdef WINRT_DIAGNOSTICS get_diagnostics_info().add_query(); #endif if (!ptr) { code = 0; return nullptr; } void* result{}; code = ptr->QueryInterface(guid_of(), &result); return wrap_as_result(result); } template auto try_as_with_reason(From ptr, hresult& code) noexcept { return ptr->template try_as_with_reason(code); } } WINRT_EXPORT namespace winrt::Windows::Foundation { struct IUnknown { IUnknown() noexcept = default; IUnknown(std::nullptr_t) noexcept {} void* operator new(size_t) = delete; IUnknown(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast(ptr)) { } IUnknown(IUnknown const& other) noexcept : m_ptr(other.m_ptr) { add_ref(); } IUnknown(IUnknown&& other) noexcept : m_ptr(std::exchange(other.m_ptr, {})) { } ~IUnknown() noexcept { release_ref(); } IUnknown& operator=(IUnknown const& other) noexcept { if (this != &other) { release_ref(); m_ptr = other.m_ptr; add_ref(); } return*this; } IUnknown& operator=(IUnknown&& other) noexcept { if (this != &other) { release_ref(); m_ptr = std::exchange(other.m_ptr, {}); } return*this; } explicit operator bool() const noexcept { return nullptr != m_ptr; } IUnknown& operator=(std::nullptr_t) noexcept { release_ref(); return*this; } template auto as() const { return impl::as(m_ptr); } template auto try_as() const noexcept { return impl::try_as(m_ptr); } template auto try_as_with_reason(hresult& code) const noexcept { return impl::try_as_with_reason(m_ptr, code); } template void as(To& to) const { to = as>(); } template bool try_as(To& to) const noexcept { if constexpr (impl::is_com_interface_v || !std::is_same_v>) { to = try_as>(); return static_cast(to); } else { auto result = try_as(); to = result.has_value() ? result.value() : impl::empty_value(); return result.has_value(); } } hresult as(guid const& id, void** result) const noexcept { return m_ptr->QueryInterface(id, result); } friend void swap(IUnknown& left, IUnknown& right) noexcept { std::swap(left.m_ptr, right.m_ptr); } private: void add_ref() const noexcept { if (m_ptr) { m_ptr->AddRef(); } } void release_ref() noexcept { if (m_ptr) { unconditional_release_ref(); } } WINRT_IMPL_NOINLINE void unconditional_release_ref() noexcept { std::exchange(m_ptr, {})->Release(); } impl::unknown_abi* m_ptr{}; }; } WINRT_EXPORT namespace winrt { template , int> = 0> auto get_abi(T const& object) noexcept { return reinterpret_cast const&>(object); } template , int> = 0> auto put_abi(T& object) noexcept { if constexpr (!std::is_trivially_destructible_v) { object = {}; } return reinterpret_cast*>(&object); } template , int> = 0> void copy_from_abi(T& object, V&& value) { object = reinterpret_cast(value); } template , int> = 0> void copy_to_abi(T const& object, V& value) { reinterpret_cast(value) = object; } template > && !std::is_convertible_v, int> = 0> auto detach_abi(T&& object) { impl::abi_t result{}; reinterpret_cast(result) = std::move(object); return result; } inline void* get_abi(Windows::Foundation::IUnknown const& object) noexcept { return *(void**)(&object); } inline void** put_abi(Windows::Foundation::IUnknown& object) noexcept { object = nullptr; return reinterpret_cast(&object); } inline void attach_abi(Windows::Foundation::IUnknown& object, void* value) noexcept { object = nullptr; *put_abi(object) = value; } inline void* detach_abi(Windows::Foundation::IUnknown& object) noexcept { void* temp = get_abi(object); *reinterpret_cast(&object) = nullptr; return temp; } inline void* detach_abi(Windows::Foundation::IUnknown&& object) noexcept { void* temp = get_abi(object); *reinterpret_cast(&object) = nullptr; return temp; } constexpr void* detach_abi(std::nullptr_t) noexcept { return nullptr; } inline void copy_from_abi(Windows::Foundation::IUnknown& object, void* value) noexcept { object = nullptr; if (value) { static_cast(value)->AddRef(); *put_abi(object) = value; } } inline void copy_to_abi(Windows::Foundation::IUnknown const& object, void*& value) noexcept { WINRT_ASSERT(value == nullptr); value = get_abi(object); if (value) { static_cast(value)->AddRef(); } } inline ::IUnknown* get_unknown(Windows::Foundation::IUnknown const& object) noexcept { return static_cast<::IUnknown*>(get_abi(object)); } } WINRT_EXPORT namespace winrt::Windows::Foundation { inline bool operator==(IUnknown const& left, IUnknown const& right) noexcept { if (get_abi(left) == get_abi(right)) { return true; } if (!left || !right) { return false; } return get_abi(left.try_as()) == get_abi(right.try_as()); } inline bool operator!=(IUnknown const& left, IUnknown const& right) noexcept { return !(left == right); } inline bool operator<(IUnknown const& left, IUnknown const& right) noexcept { if (get_abi(left) == get_abi(right)) { return false; } if (!left || !right) { return get_abi(left) < get_abi(right); } return get_abi(left.try_as()) < get_abi(right.try_as()); } inline bool operator>(IUnknown const& left, IUnknown const& right) noexcept { return right < left; } inline bool operator<=(IUnknown const& left, IUnknown const& right) noexcept { return !(right < left); } inline bool operator>=(IUnknown const& left, IUnknown const& right) noexcept { return !(left < right); } struct IInspectable : IUnknown { IInspectable(std::nullptr_t = nullptr) noexcept {} IInspectable(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} }; } WINRT_EXPORT namespace winrt { template struct com_ptr; } namespace winrt::impl { struct capture_decay { void** result; template operator T** () { return reinterpret_cast(result); } }; template int32_t capture_to(void**result, F function, Args&& ...args) { return function(args..., guid_of(), capture_decay{ result }); } template || std::is_union_v, int> = 0> int32_t capture_to(void** result, O* object, M method, Args&& ...args) { return (object->*method)(args..., guid_of(), capture_decay{ result }); } template int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args); } WINRT_EXPORT namespace winrt { template struct com_ptr { using type = impl::abi_t; com_ptr(std::nullptr_t = nullptr) noexcept {} com_ptr(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast(ptr)) { } com_ptr(com_ptr const& other) noexcept : m_ptr(other.m_ptr) { add_ref(); } template com_ptr(com_ptr const& other) noexcept : m_ptr(other.m_ptr) { add_ref(); } template com_ptr(com_ptr&& other) noexcept : m_ptr(std::exchange(other.m_ptr, {})) { } ~com_ptr() noexcept { release_ref(); } com_ptr& operator=(com_ptr const& other) noexcept { copy_ref(other.m_ptr); return*this; } com_ptr& operator=(com_ptr&& other) noexcept { if (this != &other) { release_ref(); m_ptr = std::exchange(other.m_ptr, {}); } return*this; } template com_ptr& operator=(com_ptr const& other) noexcept { copy_ref(other.m_ptr); return*this; } template com_ptr& operator=(com_ptr&& other) noexcept { release_ref(); m_ptr = std::exchange(other.m_ptr, {}); return*this; } explicit operator bool() const noexcept { return m_ptr != nullptr; } auto operator->() const noexcept { return m_ptr; } T& operator*() const noexcept { return *m_ptr; } type* get() const noexcept { return m_ptr; } type** put() noexcept { release_ref(); return &m_ptr; } void** put_void() noexcept { return reinterpret_cast(put()); } void attach(type* value) noexcept { release_ref(); *put() = value; } type* detach() noexcept { return std::exchange(m_ptr, {}); } friend void swap(com_ptr& left, com_ptr& right) noexcept { std::swap(left.m_ptr, right.m_ptr); } template auto as() const { return impl::as(m_ptr); } template auto try_as() const noexcept { return impl::try_as(m_ptr); } template void as(To& to) const { to = as>(); } template bool try_as(To& to) const noexcept { if constexpr (impl::is_com_interface_v || !std::is_same_v>) { to = try_as>(); return static_cast(to); } else { auto result = try_as(); to = result.has_value() ? result.value() : impl::empty_value(); return result.has_value(); } } hresult as(guid const& id, void** result) const noexcept { return m_ptr->QueryInterface(id, result); } void copy_from(type* other) noexcept { copy_ref(other); } void copy_to(type** other) const noexcept { add_ref(); *other = m_ptr; } template bool try_capture(Args&&...args) { return impl::capture_to(put_void(), std::forward(args)...) >= 0; } template void capture(Args&&...args) { check_hresult(impl::capture_to(put_void(), std::forward(args)...)); } private: void copy_ref(type* other) noexcept { if (m_ptr != other) { release_ref(); m_ptr = other; add_ref(); } } void add_ref() const noexcept { if (m_ptr) { const_cast*>(m_ptr)->AddRef(); } } void release_ref() noexcept { if (m_ptr) { unconditional_release_ref(); } } WINRT_IMPL_NOINLINE void unconditional_release_ref() noexcept { std::exchange(m_ptr, {})->Release(); } template friend struct com_ptr; type* m_ptr{}; }; template impl::com_ref try_capture(Args&& ...args) { void* result{}; impl::capture_to(&result, std::forward(args)...); return { result, take_ownership_from_abi }; } template impl::com_ref capture(Args&& ...args) { void* result{}; check_hresult(impl::capture_to(&result, std::forward(args)...)); return { result, take_ownership_from_abi }; } template auto get_abi(com_ptr const& object) noexcept { return object.get(); } template auto put_abi(com_ptr& object) noexcept { return object.put_void(); } template void attach_abi(com_ptr& object, impl::abi_t* value) noexcept { object.attach(value); } template auto detach_abi(com_ptr& object) noexcept { return object.detach(); } template bool operator==(com_ptr const& left, com_ptr const& right) noexcept { return get_abi(left) == get_abi(right); } template bool operator==(com_ptr const& left, std::nullptr_t) noexcept { return get_abi(left) == nullptr; } template bool operator==(std::nullptr_t, com_ptr const& right) noexcept { return nullptr == get_abi(right); } template bool operator!=(com_ptr const& left, com_ptr const& right) noexcept { return !(left == right); } template bool operator!=(com_ptr const& left, std::nullptr_t) noexcept { return !(left == nullptr); } template bool operator!=(std::nullptr_t, com_ptr const& right) noexcept { return !(nullptr == right); } template bool operator<(com_ptr const& left, com_ptr const& right) noexcept { return get_abi(left) < get_abi(right); } template bool operator>(com_ptr const& left, com_ptr const& right) noexcept { return right < left; } template bool operator<=(com_ptr const& left, com_ptr const& right) noexcept { return !(right < left); } template bool operator>=(com_ptr const& left, com_ptr const& right) noexcept { return !(left < right); } } namespace winrt::impl { template int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) { return (object.get()->*(method))(args..., guid_of(), capture_decay{ result }); } } template void** IID_PPV_ARGS_Helper(winrt::com_ptr* ptr) noexcept { return winrt::put_abi(*ptr); } namespace winrt::impl { struct atomic_ref_count { atomic_ref_count() noexcept = default; explicit atomic_ref_count(uint32_t count) noexcept : m_count(count) { } uint32_t operator=(uint32_t count) noexcept { return m_count = count; } uint32_t operator++() noexcept { return static_cast(m_count.fetch_add(1, std::memory_order_relaxed) + 1); } uint32_t operator--() noexcept { auto const remaining = m_count.fetch_sub(1, std::memory_order_release) - 1; if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); } else if (remaining < 0) { abort(); } return static_cast(remaining); } operator uint32_t() const noexcept { return static_cast(m_count); } private: std::atomic m_count; }; constexpr uint32_t hstring_reference_flag{ 1 }; struct hstring_header { uint32_t flags; uint32_t length; uint32_t padding1; uint32_t padding2; wchar_t const* ptr; }; struct shared_hstring_header : hstring_header { atomic_ref_count count; wchar_t buffer[1]; }; inline void release_hstring(hstring_header* handle) noexcept { WINRT_ASSERT((handle->flags & hstring_reference_flag) == 0); if (0 == --static_cast(handle)->count) { WINRT_IMPL_HeapFree(WINRT_IMPL_GetProcessHeap(), 0, handle); } } inline shared_hstring_header* precreate_hstring_on_heap(uint32_t length) { WINRT_ASSERT(length != 0); uint64_t bytes_required = static_cast(sizeof(shared_hstring_header)) + static_cast(sizeof(wchar_t)) * static_cast(length); if (bytes_required > UINT_MAX) { throw std::invalid_argument("length"); } auto header = static_cast(WINRT_IMPL_HeapAlloc(WINRT_IMPL_GetProcessHeap(), 0, static_cast(bytes_required))); if (!header) { throw std::bad_alloc(); } header->flags = 0; header->length = length; header->ptr = header->buffer; header->count = 1; header->buffer[length] = 0; return header; } inline hstring_header* create_hstring_on_heap(wchar_t const* value, uint32_t length) { if (!length) { return nullptr; } auto header = precreate_hstring_on_heap(length); memcpy_s(header->buffer, sizeof(wchar_t) * length, value, sizeof(wchar_t) * length); return header; } inline void create_hstring_on_stack(hstring_header& header, wchar_t const* value, uint32_t length) noexcept { WINRT_ASSERT(value); WINRT_ASSERT(length != 0); if (value[length] != 0) { abort(); } header.flags = hstring_reference_flag; header.length = length; header.ptr = value; } inline hstring_header* duplicate_hstring(hstring_header* handle) { if (!handle) { return nullptr; } else if ((handle->flags & hstring_reference_flag) == 0) { ++static_cast(handle)->count; return handle; } else { return create_hstring_on_heap(handle->ptr, handle->length); } } struct hstring_traits { using type = hstring_header*; static void close(type value) noexcept { release_hstring(value); } static constexpr type invalid() noexcept { return nullptr; } }; } WINRT_EXPORT namespace winrt { struct hstring { using value_type = wchar_t; using size_type = uint32_t; using const_reference = value_type const&; using pointer = value_type*; using const_pointer = value_type const*; using const_iterator = const_pointer; using const_reverse_iterator = std::reverse_iterator; hstring() noexcept = default; hstring(void* ptr, take_ownership_from_abi_t) noexcept : m_handle(static_cast(ptr)) { } hstring(hstring const& value) : m_handle(impl::duplicate_hstring(value.m_handle.get())) {} hstring& operator=(hstring const& value) { m_handle.attach(impl::duplicate_hstring(value.m_handle.get())); return*this; } hstring(hstring&&) noexcept = default; hstring& operator=(hstring&&) = default; hstring(std::nullptr_t) = delete; hstring& operator=(std::nullptr_t) = delete; hstring(std::initializer_list value) : hstring(value.begin(), static_cast(value.size())) {} hstring(wchar_t const* value) : hstring(std::wstring_view(value)) {} hstring(wchar_t const* value, size_type size) : m_handle(impl::create_hstring_on_heap(value, size)) {} explicit hstring(std::wstring_view const& value) : hstring(value.data(), static_cast(value.size())) {} hstring& operator=(std::wstring_view const& value) { return *this = hstring{ value }; } hstring& operator=(wchar_t const* const value) { return *this = hstring{ value }; } hstring& operator=(std::initializer_list value) { return *this = hstring{ value }; } void clear() noexcept { m_handle.close(); } operator std::wstring_view() const noexcept { if (m_handle) { return{ m_handle.get()->ptr, m_handle.get()->length }; } else { return { L"", 0 }; } } const_reference operator[](size_type pos) const noexcept { WINRT_ASSERT(pos < size()); return*(begin() + pos); } const_reference front() const noexcept { WINRT_ASSERT(!empty()); return*begin(); } const_reference back() const noexcept { WINRT_ASSERT(!empty()); return*(end() - 1); } const_pointer data() const noexcept { return c_str(); } const_pointer c_str() const noexcept { if (!empty()) { return begin(); } else { return L""; } } const_iterator begin() const noexcept { if (m_handle) { return m_handle.get()->ptr; } else { return {}; } } const_iterator cbegin() const noexcept { return begin(); } const_iterator end() const noexcept { if (m_handle) { return m_handle.get()->ptr + m_handle.get()->length; } else { return {}; } } const_iterator cend() const noexcept { return end(); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } const_reverse_iterator crbegin() const noexcept { return rbegin(); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } const_reverse_iterator crend() const noexcept { return rend(); } #ifdef __cpp_lib_starts_ends_with bool starts_with(wchar_t const value) const noexcept { return operator std::wstring_view().starts_with(value); } bool starts_with(std::wstring_view const another) const noexcept { return operator std::wstring_view().starts_with(another); } bool starts_with(const wchar_t* const pointer) const noexcept { return operator std::wstring_view().starts_with(pointer); } bool ends_with(wchar_t const value) const noexcept { return operator std::wstring_view().ends_with(value); } bool ends_with(std::wstring_view const another) const noexcept { return operator std::wstring_view().ends_with(another); } bool ends_with(const wchar_t* const pointer) const noexcept { return operator std::wstring_view().ends_with(pointer); } #endif bool empty() const noexcept { return !m_handle; } size_type size() const noexcept { if (m_handle) { return m_handle.get()->length; } else { return 0; } } friend void swap(hstring& left, hstring& right) noexcept { swap(left.m_handle, right.m_handle); } private: handle_type m_handle; }; inline void* get_abi(hstring const& object) noexcept { return *(void**)(&object); } inline void** put_abi(hstring& object) noexcept { object.clear(); return reinterpret_cast(&object); } inline void attach_abi(hstring& object, void* value) noexcept { object.clear(); *put_abi(object) = value; } inline void* detach_abi(hstring& object) noexcept { void* temp = get_abi(object); *reinterpret_cast(&object) = nullptr; return temp; } inline void* detach_abi(hstring&& object) noexcept { return detach_abi(object); } inline void copy_from_abi(hstring& object, void* value) { attach_abi(object, impl::duplicate_hstring(static_cast(value))); } inline void copy_to_abi(hstring const& object, void*& value) { WINRT_ASSERT(value == nullptr); value = impl::duplicate_hstring(static_cast(get_abi(object))); } inline void* detach_abi(std::wstring_view const& value) { return impl::create_hstring_on_heap(value.data(), static_cast(value.size())); } inline void* detach_abi(wchar_t const* const value) { return impl::create_hstring_on_heap(value, static_cast(wcslen(value))); } } #ifdef __cpp_lib_format template<> struct std::formatter : std::formatter {}; #endif namespace winrt::impl { template <> struct abi { using type = void*; }; template <> struct category { using type = basic_category; }; struct hstring_builder { hstring_builder(hstring_builder const&) = delete; hstring_builder& operator=(hstring_builder const&) = delete; explicit hstring_builder(uint32_t const size) : m_handle(impl::precreate_hstring_on_heap(size)) { } wchar_t* data() noexcept { return const_cast(m_handle.get()->ptr); } hstring to_hstring() { return { m_handle.detach(), take_ownership_from_abi }; } private: handle_type m_handle; }; template struct bind_in { bind_in(T const& object) noexcept : object(object) { } T const& object; #if !defined(__GNUC__) || defined(__clang__) template operator R const& () const noexcept { return reinterpret_cast(object); } #else // HACK: GCC does not handle template deduction of const T& conversion // function according to CWG issue 976. To make this compile on GCC, // we have to intentionally drop the const qualifier. // Ref: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61663 template operator R& () const noexcept { return const_cast(reinterpret_cast(object)); } #endif }; template struct bind_out { bind_out(T& object) noexcept : object(object) { } T& object; operator void** () const noexcept { if constexpr (std::is_same_v) { object.clear(); } else { object = nullptr; } return (void**)(&object); } template operator R* () const noexcept { if constexpr (!std::is_trivially_destructible_v) { object = {}; } return reinterpret_cast(&object); } }; template inline hstring hstring_convert(T value) { static_assert(std::is_arithmetic_v); char temp[32]; std::to_chars_result result; if constexpr (std::is_integral_v) { result = std::to_chars(std::begin(temp), std::end(temp), value); } else { // Floating point result = std::to_chars(std::begin(temp), std::end(temp), value, std::chars_format::general); } WINRT_ASSERT(result.ec == std::errc{}); wchar_t buffer[32]; auto end = std::copy(std::begin(temp), result.ptr, buffer); return hstring{ std::wstring_view{ buffer, static_cast(end - buffer)} }; } #if __cpp_lib_format >= 202207L template inline hstring base_format(Args&&... args) { // don't forward because an object could be moved-from, causing issues // for the second format call. // not forwarding lets us take both rvalues and lvalues but pass them // further down as an lvalue ref. some types can only be formatted // when non-const (e.g. ranges::filter_view) so taking a const reference // as parameter wouldn't work for all scenarios. auto const size = std::formatted_size(args...); WINRT_ASSERT(size < UINT_MAX); auto const size32 = static_cast(size); hstring_builder builder(size32); WINRT_VERIFY_(size32, std::format_to_n(builder.data(), size32, args...).size); return builder.to_hstring(); } #endif } WINRT_EXPORT namespace winrt { #if __cpp_lib_format >= 202207L template inline hstring format(std::wformat_string const fmt, Args&&... args) { return impl::base_format(fmt, args...); } template inline hstring format(std::locale const& loc, std::wformat_string const fmt, Args&&... args) { return impl::base_format(loc, fmt, args...); } #endif inline bool embedded_null(hstring const& value) noexcept { return std::any_of(value.begin(), value.end(), [](auto item) { return item == 0; }); } inline hstring to_hstring(uint8_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(int8_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(uint16_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(int16_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(uint32_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(int32_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(uint64_t value) { return impl::hstring_convert(value); } inline hstring to_hstring(int64_t value) { return impl::hstring_convert(value); } #if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 14000 inline hstring to_hstring(float value) { return impl::hstring_convert(value); } inline hstring to_hstring(double value) { return impl::hstring_convert(value); } #endif inline hstring to_hstring(char16_t value) { wchar_t buffer[2] = { value, 0 }; return hstring{ std::wstring_view{ buffer, 1 } }; } inline hstring to_hstring(hstring const& value) noexcept { return value; } template , int> = 0> hstring to_hstring(T const value) { if (value) { return hstring{ L"true" }; } else { return hstring{ L"false" }; } } inline hstring to_hstring(guid const& value) { wchar_t buffer[40]; //{00000000-0000-0000-0000-000000000000} swprintf_s(buffer, L"{%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", value.Data1, value.Data2, value.Data3, value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7]); return hstring{ buffer }; } template , int> = 0> hstring to_hstring(T const& value) { std::string_view const view(value); int const size = WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), nullptr, 0); if (size == 0) { return{}; } impl::hstring_builder result(size); WINRT_VERIFY_(size, WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), result.data(), size)); return result.to_hstring(); } inline std::string to_string(std::wstring_view value) { int const size = WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); if (size == 0) { return{}; } std::string result(size, '?'); WINRT_VERIFY_(size, WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), result.data(), size, nullptr, nullptr)); return result; } } WINRT_EXPORT namespace winrt::param { struct hstring { #ifdef _MSC_VER #pragma warning(suppress: 26495) #endif hstring() noexcept : m_handle(nullptr) {} hstring(hstring const& values) = delete; hstring& operator=(hstring const& values) = delete; hstring(std::nullptr_t) = delete; #ifdef _MSC_VER #pragma warning(suppress: 26495) #endif hstring(winrt::hstring const& value) noexcept : m_handle(get_abi(value)) { } hstring(std::wstring_view const& value) noexcept { create_string_reference(value.data(), value.size()); } hstring(std::wstring const& value) noexcept { create_string_reference(value.data(), value.size()); } hstring(wchar_t const* const value) noexcept { create_string_reference(value, wcslen(value)); } operator winrt::hstring const&() const noexcept { return *reinterpret_cast(this); } private: void create_string_reference(wchar_t const* const data, size_t size) noexcept { WINRT_ASSERT(size < UINT_MAX); auto size32 = static_cast(size); if (size32 == 0) { m_handle = nullptr; } else { impl::create_hstring_on_stack(m_header, data, size32); m_handle = &m_header; } } void* m_handle; impl::hstring_header m_header; }; inline void* get_abi(hstring const& object) noexcept { return *(void**)(&object); } } namespace winrt::impl { template using param_type = std::conditional_t, param::hstring, T>; } WINRT_EXPORT namespace winrt { inline bool operator==(hstring const& left, hstring const& right) noexcept { return std::wstring_view(left) == std::wstring_view(right); } inline bool operator==(hstring const& left, std::wstring const& right) noexcept { return std::wstring_view(left) == right; } inline bool operator==(std::wstring const& left, hstring const& right) noexcept { return left == std::wstring_view(right); } inline bool operator==(hstring const& left, wchar_t const* right) noexcept { return std::wstring_view(left) == right; } inline bool operator==(wchar_t const* left, hstring const& right) noexcept { return left == std::wstring_view(right); } bool operator==(hstring const& left, std::nullptr_t) = delete; bool operator==(std::nullptr_t, hstring const& right) = delete; inline bool operator<(hstring const& left, hstring const& right) noexcept { return std::wstring_view(left) < std::wstring_view(right); } inline bool operator<(std::wstring const& left, hstring const& right) noexcept { return left < std::wstring_view(right); } inline bool operator<(hstring const& left, std::wstring const& right) noexcept { return std::wstring_view(left) < right; } inline bool operator<(hstring const& left, wchar_t const* right) noexcept { return std::wstring_view(left) < right; } inline bool operator<(wchar_t const* left, hstring const& right) noexcept { return left < std::wstring_view(right); } bool operator<(hstring const& left, std::nullptr_t) = delete; bool operator<(std::nullptr_t, hstring const& right) = delete; inline bool operator!=(hstring const& left, hstring const& right) noexcept { return !(left == right); } inline bool operator>(hstring const& left, hstring const& right) noexcept { return right < left; } inline bool operator<=(hstring const& left, hstring const& right) noexcept { return !(right < left); } inline bool operator>=(hstring const& left, hstring const& right) noexcept { return !(left < right); } inline bool operator!=(hstring const& left, std::wstring const& right) noexcept { return !(left == right); } inline bool operator>(hstring const& left, std::wstring const& right) noexcept { return right < left; } inline bool operator<=(hstring const& left, std::wstring const& right) noexcept { return !(right < left); } inline bool operator>=(hstring const& left, std::wstring const& right) noexcept { return !(left < right); } inline bool operator!=(std::wstring const& left, hstring const& right) noexcept { return !(left == right); } inline bool operator>(std::wstring const& left, hstring const& right) noexcept { return right < left; } inline bool operator<=(std::wstring const& left, hstring const& right) noexcept { return !(right < left); } inline bool operator>=(std::wstring const& left, hstring const& right) noexcept { return !(left < right); } inline bool operator!=(hstring const& left, wchar_t const* right) noexcept { return !(left == right); } inline bool operator>(hstring const& left, wchar_t const* right) noexcept { return right < left; } inline bool operator<=(hstring const& left, wchar_t const* right) noexcept { return !(right < left); } inline bool operator>=(hstring const& left, wchar_t const* right) noexcept { return !(left < right); } inline bool operator!=(wchar_t const* left, hstring const& right) noexcept { return !(left == right); } inline bool operator>(wchar_t const* left, hstring const& right) noexcept { return right < left; } inline bool operator<=(wchar_t const* left, hstring const& right) noexcept { return !(right < left); } inline bool operator>=(wchar_t const* left, hstring const& right) noexcept { return !(left < right); } bool operator!=(hstring const& left, std::nullptr_t right) = delete; bool operator>(hstring const& left, std::nullptr_t right) = delete; bool operator<=(hstring const& left, std::nullptr_t right) = delete; bool operator>=(hstring const& left, std::nullptr_t right) = delete; bool operator!=(std::nullptr_t left, hstring const& right) = delete; bool operator>(std::nullptr_t left, hstring const& right) = delete; bool operator<=(std::nullptr_t left, hstring const& right) = delete; bool operator>=(std::nullptr_t left, hstring const& right) = delete; } namespace winrt::impl { inline hstring concat_hstring(std::wstring_view const& left, std::wstring_view const& right) { auto size = static_cast(left.size() + right.size()); if (size == 0) { return{}; } hstring_builder text(size); memcpy_s(text.data(), left.size() * sizeof(wchar_t), left.data(), left.size() * sizeof(wchar_t)); memcpy_s(text.data() + left.size(), right.size() * sizeof(wchar_t), right.data(), right.size() * sizeof(wchar_t)); return text.to_hstring(); } } WINRT_EXPORT namespace winrt { inline hstring operator+(hstring const& left, hstring const& right) { return impl::concat_hstring(left, right); } inline hstring operator+(hstring const& left, std::wstring const& right) { return impl::concat_hstring(left, right); } inline hstring operator+(std::wstring const& left, hstring const& right) { return impl::concat_hstring(left, right); } inline hstring operator+(hstring const& left, wchar_t const* right) { return impl::concat_hstring(left, right); } inline hstring operator+(wchar_t const* left, hstring const& right) { return impl::concat_hstring(left, right); } inline hstring operator+(hstring const& left, wchar_t right) { return impl::concat_hstring(left, std::wstring_view(&right, 1)); } inline hstring operator+(wchar_t left, hstring const& right) { return impl::concat_hstring(std::wstring_view(&left, 1), right); } hstring operator+(hstring const& left, std::nullptr_t) = delete; hstring operator+(std::nullptr_t, hstring const& right) = delete; inline hstring operator+(hstring const& left, std::wstring_view const& right) { return impl::concat_hstring(left, right); } inline hstring operator+(std::wstring_view const& left, hstring const& right) { return impl::concat_hstring(left, right); } #ifndef WINRT_LEAN_AND_MEAN inline std::wostream& operator<<(std::wostream& stream, hstring const& string) { stream << static_cast(string); return stream; } #endif } WINRT_EXPORT namespace winrt { template struct array_view { using value_type = T; using size_type = uint32_t; using reference = value_type&; using const_reference = value_type const&; using pointer = value_type*; using const_pointer = value_type const*; using iterator = value_type*; using const_iterator = value_type const*; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; array_view() noexcept = default; array_view(pointer data, size_type size) noexcept : m_data(data), m_size(size) {} array_view(pointer first, pointer last) noexcept : m_data(first), m_size(static_cast(last - first)) {} array_view(std::initializer_list value) noexcept : array_view(value.begin(), static_cast(value.size())) {} #ifdef __cpp_lib_span template array_view(std::span span) noexcept : array_view(span.data(), static_cast(span.size())) { WINRT_ASSERT(span.size() <= UINT_MAX); } operator std::span() const noexcept { return { m_data, m_size }; } #endif template array_view(C(&value)[N]) noexcept : array_view(value, N) {} template array_view(std::vector& value) noexcept : array_view(data(value), static_cast(value.size())) { } template array_view(std::vector const& value) noexcept : array_view(data(value), static_cast(value.size())) { } template array_view(std::array& value) noexcept : array_view(value.data(), static_cast(value.size())) {} template array_view(std::array const& value) noexcept : array_view(value.data(), static_cast(value.size())) {} template array_view(array_view const& other, std::enable_if_t, int> = 0) noexcept : array_view(other.data(), other.size()) {} reference operator[](size_type const pos) noexcept { WINRT_ASSERT(pos < size()); return m_data[pos]; } const_reference operator[](size_type const pos) const noexcept { WINRT_ASSERT(pos < size()); return m_data[pos]; } reference at(size_type const pos) { if (size() <= pos) { throw std::out_of_range("Invalid array subscript"); } return m_data[pos]; } const_reference at(size_type const pos) const { if (size() <= pos) { throw std::out_of_range("Invalid array subscript"); } return m_data[pos]; } reference front() noexcept { WINRT_ASSERT(m_size > 0); return*m_data; } const_reference front() const noexcept { WINRT_ASSERT(m_size > 0); return*m_data; } reference back() noexcept { WINRT_ASSERT(m_size > 0); return m_data[m_size - 1]; } const_reference back() const noexcept { WINRT_ASSERT(m_size > 0); return m_data[m_size - 1]; } pointer data() const noexcept { return m_data; } iterator begin() noexcept { return m_data; } const_iterator begin() const noexcept { return m_data; } const_iterator cbegin() const noexcept { return m_data; } iterator end() noexcept { return m_data + m_size; } const_iterator end() const noexcept { return m_data + m_size; } const_iterator cend() const noexcept { return m_data + m_size; } reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } const_reverse_iterator crbegin() const noexcept { return rbegin(); } reverse_iterator rend() noexcept { return reverse_iterator(begin()); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } const_reverse_iterator crend() const noexcept { return rend(); } bool empty() const noexcept { return m_size == 0; } size_type size() const noexcept { return m_size; } protected: pointer m_data{ nullptr }; size_type m_size{ 0 }; private: template auto data(std::vector const& value) noexcept { static_assert(!std::is_same_v, "Cannot use std::vector as an array_view. Consider std::array or std::unique_ptr."); return value.data(); } template auto data(std::vector& value) noexcept { static_assert(!std::is_same_v, "Cannot use std::vector as an array_view. Consider std::array or std::unique_ptr."); return value.data(); } }; template array_view(C(&value)[N]) -> array_view; template array_view(std::vector& value) -> array_view; template array_view(std::vector const& value) -> array_view; template array_view(std::array& value) -> array_view; template array_view(std::array const& value) -> array_view; #ifdef __cpp_lib_span template array_view(std::span& value) -> array_view; template array_view(std::span const& value) -> array_view; #endif template struct com_array : array_view { using typename array_view::value_type; using typename array_view::size_type; using typename array_view::reference; using typename array_view::const_reference; using typename array_view::pointer; using typename array_view::const_pointer; using typename array_view::iterator; using typename array_view::const_iterator; using typename array_view::reverse_iterator; using typename array_view::const_reverse_iterator; com_array(com_array const&) = delete; com_array& operator=(com_array const&) = delete; com_array() noexcept = default; explicit com_array(size_type const count) : com_array(count, value_type()) {} com_array(void* ptr, uint32_t const count, take_ownership_from_abi_t) noexcept : array_view(static_cast(ptr), static_cast(ptr) + count) { } com_array(size_type const count, value_type const& value) { alloc(count); std::uninitialized_fill_n(this->m_data, count, value); } template ::difference_type>> com_array(InIt first, InIt last) { alloc(static_cast(std::distance(first, last))); std::uninitialized_copy(first, last, this->begin()); } template explicit com_array(std::vector const& value) : com_array(value.begin(), value.end()) {} template explicit com_array(std::array const& value) : com_array(value.begin(), value.end()) {} #ifdef __cpp_lib_span template explicit com_array(std::span span) noexcept : com_array(span.data(), span.data() + span.size()) { WINRT_ASSERT(span.size() <= UINT_MAX); } #endif template explicit com_array(U const(&value)[N]) : com_array(value, value + N) {} com_array(std::initializer_list value) : com_array(value.begin(), value.end()) {} template >> com_array(std::initializer_list value) : com_array(value.begin(), value.end()) {} com_array(com_array&& other) noexcept : array_view(other.m_data, other.m_size) { other.m_data = nullptr; other.m_size = 0; } com_array& operator=(com_array&& other) noexcept { clear(); this->m_data = other.m_data; this->m_size = other.m_size; other.m_data = nullptr; other.m_size = 0; return*this; } ~com_array() noexcept { clear(); } void clear() noexcept { if (this->m_data == nullptr) { return; } std::destroy(this->begin(), this->end()); WINRT_IMPL_CoTaskMemFree(this->m_data); this->m_data = nullptr; this->m_size = 0; } friend void swap(com_array& left, com_array& right) noexcept { std::swap(left.m_data, right.m_data); std::swap(left.m_size, right.m_size); } private: void alloc(size_type const size) { WINRT_ASSERT(this->empty()); if (0 != size) { this->m_data = static_cast(WINRT_IMPL_CoTaskMemAlloc(size * sizeof(value_type))); if (this->m_data == nullptr) { throw std::bad_alloc(); } this->m_size = size; } } std::pair> detach_abi() noexcept { #ifdef _MSC_VER // https://github.com/microsoft/cppwinrt/pull/1165 std::pair> result; memset(&result, 0, sizeof(result)); result.first = this->size(); result.second = *reinterpret_cast*>(this); memset(this, 0, sizeof(com_array)); #else std::pair> result(this->size(), *reinterpret_cast*>(this)); this->m_data = nullptr; this->m_size = 0; #endif return result; } template friend std::pair> detach_abi(com_array& object) noexcept; }; template com_array(uint32_t, C const&) -> com_array>; template ::difference_type>> com_array(InIt, InIt) -> com_array::value_type>>; template com_array(std::vector const&) -> com_array>; template com_array(std::array const&) -> com_array>; template com_array(C const(&)[N]) -> com_array>; template com_array(std::initializer_list) -> com_array>; #ifdef __cpp_lib_span template com_array(std::span const& value) -> com_array>; #endif namespace impl { template inline constexpr bool array_comparable = std::is_same_v, std::remove_cv_t>; } template , int> = 0> bool operator==(array_view const& left, array_view const& right) noexcept { return std::equal(left.begin(), left.end(), right.begin(), right.end()); } template , int> = 0> bool operator<(array_view const& left, array_view const& right) noexcept { return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end()); } template , int> = 0> bool operator!=(array_view const& left, array_view const& right) noexcept { return !(left == right); } template , int> = 0> bool operator>(array_view const& left, array_view const& right) noexcept { return right < left; } template , int> = 0> bool operator<=(array_view const& left, array_view const& right) noexcept { return !(right < left); } template , int> = 0> bool operator>=(array_view const& left, array_view const& right) noexcept { return !(left < right); } template auto get_abi(array_view object) noexcept { auto data = object.size() ? object.data() : (T*)alignof(T); if constexpr (std::is_base_of_v) { return (void**)data; } else { return reinterpret_cast>>(const_cast*>(data)); } } template auto put_abi(array_view object) noexcept { if constexpr (!std::is_trivially_destructible_v) { std::fill(object.begin(), object.end(), impl::empty_value()); } return get_abi(object); } template auto put_abi(com_array& object) noexcept { object.clear(); return reinterpret_cast*>(&object); } template std::pair> detach_abi(com_array& object) noexcept { return object.detach_abi(); } template auto detach_abi(com_array&& object) noexcept { return detach_abi(object); } } namespace winrt::impl { template struct array_size_proxy { array_size_proxy& operator=(array_size_proxy const&) = delete; array_size_proxy(com_array& value) noexcept : m_value(value) {} ~array_size_proxy() noexcept { WINRT_ASSERT(m_value.data() || (!m_value.data() && m_size == 0)); *reinterpret_cast(reinterpret_cast(&m_value) + 1) = m_size; } operator uint32_t*() noexcept { return &m_size; } operator unsigned long*() noexcept { return reinterpret_cast(&m_size); } private: com_array& m_value; uint32_t m_size{ 0 }; }; template array_size_proxy put_size_abi(com_array& object) noexcept { return array_size_proxy(object); } template struct com_array_proxy { com_array_proxy(uint32_t* size, winrt::impl::arg_out* value) noexcept : m_size(size), m_value(value) {} ~com_array_proxy() noexcept { std::tie(*m_size, *m_value) = detach_abi(m_temp); } operator com_array&() noexcept { return m_temp; } com_array_proxy(com_array_proxy const&) noexcept { // A Visual C++ compiler bug (550631) requires the copy constructor even though it is never called. WINRT_ASSERT(false); } private: uint32_t* m_size; arg_out* m_value; com_array m_temp; }; } WINRT_EXPORT namespace winrt { template auto detach_abi(uint32_t* __valueSize, impl::arg_out* value) noexcept { return impl::com_array_proxy(__valueSize, value); } inline hstring get_class_name(Windows::Foundation::IInspectable const& object) { void* value{}; check_hresult((*(impl::inspectable_abi**)&object)->GetRuntimeClassName(&value)); return { value, take_ownership_from_abi }; } inline com_array get_interfaces(Windows::Foundation::IInspectable const& object) { com_array value; check_hresult((*(impl::inspectable_abi**)&object)->GetIids(impl::put_size_abi(value), put_abi(value))); return value; } inline Windows::Foundation::TrustLevel get_trust_level(Windows::Foundation::IInspectable const& object) { Windows::Foundation::TrustLevel value{}; check_hresult((*(impl::inspectable_abi**)&object)->GetTrustLevel(&value)); return value; } } WINRT_EXPORT namespace winrt { template struct weak_ref { weak_ref(std::nullptr_t = nullptr) noexcept {} template const&, typename = std::enable_if_t const&>>> weak_ref(U&& object) { from_com_ref(static_cast const&>(object)); } [[nodiscard]] auto get() const noexcept { if (!m_ref) { return impl::com_ref{ nullptr }; } if constexpr(impl::is_implements_v) { impl::com_ref> temp; m_ref->Resolve(guid_of(), put_abi(temp)); void* result = nullptr; if (temp) { result = get_self(temp); detach_abi(temp); } return impl::com_ref{ result, take_ownership_from_abi }; } else { void* result{}; m_ref->Resolve(guid_of(), &result); return impl::com_ref{ result, take_ownership_from_abi }; } } auto put() noexcept { return m_ref.put(); } explicit operator bool() const noexcept { return static_cast(m_ref); } private: template void from_com_ref(U&& object) { if (object) { if constexpr (impl::is_implements_v) { m_ref = std::move(object->get_weak().m_ref); } else { // An access violation (crash) on the following line means that the object does not support weak references. // Avoid using weak_ref/auto_revoke with such objects. check_hresult(object.template try_as()->GetWeakReference(m_ref.put())); } } } com_ptr m_ref; }; template weak_ref(T const&)->weak_ref>; template struct impl::abi> : impl::abi> { }; template inline bool operator==(weak_ref const& left, weak_ref const& right) noexcept { return get_abi(left) == get_abi(right); } template inline bool operator==(weak_ref const& left, std::nullptr_t) noexcept { return get_abi(left) == nullptr; } template inline bool operator==(std::nullptr_t, weak_ref const& right) noexcept { return nullptr == get_abi(right); } template inline bool operator!=(weak_ref const& left, weak_ref const& right) noexcept { return !(left == right); } template inline bool operator!=(weak_ref const& left, std::nullptr_t) noexcept { return !(left == nullptr); } template inline bool operator!=(std::nullptr_t, weak_ref const& right) noexcept { return !(nullptr == right); } template weak_ref> make_weak(T const& object) { return object; } } WINRT_EXPORT namespace winrt { #if defined (WINRT_NO_MODULE_LOCK) // Defining WINRT_NO_MODULE_LOCK is appropriate for apps (executables) or pinned DLLs (that don't support unloading) // and can thus avoid the synchronization overhead imposed by the default module lock. constexpr auto get_module_lock() noexcept { struct lock { constexpr uint32_t operator++() noexcept { return 1; } constexpr uint32_t operator--() noexcept { return 0; } constexpr explicit operator bool() noexcept { return true; } }; return lock{}; } #elif defined (WINRT_CUSTOM_MODULE_LOCK) // When WINRT_CUSTOM_MODULE_LOCK is defined, you must provide an implementation of winrt::get_module_lock() // that returns an object that implements operator++ and operator--. #else // This is the default implementation for use with DllCanUnloadNow. inline impl::atomic_ref_count& get_module_lock() noexcept { static impl::atomic_ref_count s_lock; return s_lock; } #endif } namespace winrt::impl { template struct module_lock_updater; template<> struct module_lock_updater { module_lock_updater() noexcept { ++get_module_lock(); } ~module_lock_updater() noexcept { --get_module_lock(); } }; template<> struct module_lock_updater {}; using update_module_lock = module_lock_updater; inline void* load_library(wchar_t const* library) noexcept { return WINRT_IMPL_LoadLibraryExW(library, nullptr, 0x00001000 /* LOAD_LIBRARY_SEARCH_DEFAULT_DIRS */); } inline hresult get_agile_reference(winrt::guid const& iid, void* object, void** reference) noexcept { return WINRT_IMPL_RoGetAgileReference(0, iid, object, reference); } } WINRT_EXPORT namespace winrt { template struct agile_ref { agile_ref(std::nullptr_t = nullptr) noexcept {} agile_ref(impl::com_ref const& object) { if (object) { check_hresult(impl::get_agile_reference(guid_of(), winrt::get_abi(object), m_ref.put_void())); } } [[nodiscard]] impl::com_ref get() const noexcept { if (!m_ref) { return nullptr; } void* result{}; m_ref->Resolve(guid_of(), &result); return { result, take_ownership_from_abi }; } explicit operator bool() const noexcept { return static_cast(m_ref); } private: com_ptr m_ref; }; template agile_ref(T const&)->agile_ref>; template agile_ref> make_agile(T const& object) { return object; } } #if defined(_MSC_VER) #define WINRT_IMPL_RETURNADDRESS() _ReturnAddress() #elif defined(__GNUC__) #define WINRT_IMPL_RETURNADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) #else #define WINRT_IMPL_RETURNADDRESS() nullptr #endif namespace winrt::impl { struct heap_traits { using type = wchar_t*; static void close(type value) noexcept { WINRT_VERIFY(WINRT_IMPL_HeapFree(WINRT_IMPL_GetProcessHeap(), 0, value)); } static constexpr type invalid() noexcept { return nullptr; } }; struct bstr_traits { using type = wchar_t*; static void close(type value) noexcept { WINRT_IMPL_SysFreeString(value); } static constexpr type invalid() noexcept { return nullptr; } }; using bstr_handle = handle_type; inline hstring trim_hresult_message(wchar_t const* const message, uint32_t size) noexcept { wchar_t const* back = message + size - 1; while (size&& iswspace(*back)) { --size; --back; } return { message, size }; } inline hstring message_from_hresult(hresult code) noexcept { handle_type message; uint32_t const size = WINRT_IMPL_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS nullptr, code, 0x00000400, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) reinterpret_cast(message.put()), 0, nullptr); return trim_hresult_message(message.get(), size); } constexpr int32_t hresult_from_win32(uint32_t const x) noexcept { return (int32_t)(x) <= 0 ? (int32_t)(x) : (int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000); } constexpr int32_t hresult_from_nt(uint32_t const x) noexcept { return ((int32_t)((x) | 0x10000000)); } } WINRT_EXPORT namespace winrt { struct hresult_error { using from_abi_t = take_ownership_from_abi_t; static constexpr auto from_abi{ take_ownership_from_abi }; hresult_error() noexcept = default; hresult_error(hresult_error&&) = default; hresult_error& operator=(hresult_error&&) = default; hresult_error(hresult_error const& other) noexcept : m_code(other.m_code), m_info(other.m_info) { } hresult_error& operator=(hresult_error const& other) noexcept { m_code = other.m_code; m_info = other.m_info; return *this; } explicit hresult_error(hresult const code, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { originate(code, nullptr, sourceInformation); } hresult_error(hresult const code, param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { originate(code, get_abi(message), sourceInformation); } hresult_error(hresult const code, take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { com_ptr info; WINRT_IMPL_GetErrorInfo(0, info.put_void()); if ((m_info = info.try_as())) { WINRT_VERIFY_(0, m_info->GetReference(m_debug_reference.put())); if (auto info2 = m_info.try_as()) { WINRT_VERIFY_(0, info2->CapturePropagationContext(nullptr)); } } else { impl::bstr_handle legacy; if (info) { info->GetDescription(legacy.put()); } hstring message; if (legacy) { message = impl::trim_hresult_message(legacy.get(), WINRT_IMPL_SysStringLen(legacy.get())); } originate(code, get_abi(message), sourceInformation); } } hresult code() const noexcept { return m_code; } hstring message() const noexcept { if (m_info) { int32_t code{}; impl::bstr_handle fallback; impl::bstr_handle message; impl::bstr_handle unused; if (0 == m_info->GetErrorDetails(fallback.put(), &code, message.put(), unused.put())) { if (code == m_code) { if (message) { return impl::trim_hresult_message(message.get(), WINRT_IMPL_SysStringLen(message.get())); } else { return impl::trim_hresult_message(fallback.get(), WINRT_IMPL_SysStringLen(fallback.get())); } } } } return impl::message_from_hresult(m_code); } template auto try_as() const noexcept { return m_info.try_as(); } hresult to_abi() const noexcept { if (m_info) { WINRT_IMPL_SetErrorInfo(0, m_info.try_as().get()); } return m_code; } private: void originate(hresult const code, void* message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept { WINRT_VERIFY(WINRT_IMPL_RoOriginateLanguageException(code, message, nullptr)); // This is an extension point that can be filled in by other libraries (such as WIL) to get call outs when errors are // originated. This is intended for logging purposes. When possible include the std::source_information so that accurate // information is available on the caller who generated the error. if (winrt_throw_hresult_handler) { winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), code); } com_ptr info; WINRT_IMPL_GetErrorInfo(0, info.put_void()); info.try_as(m_info); } static hresult verify_error(hresult const code) noexcept { WINRT_ASSERT(code < 0); return code; } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" #endif impl::bstr_handle m_debug_reference; uint32_t m_debug_magic{ 0xAABBCCDD }; hresult m_code{ impl::error_fail }; com_ptr m_info; #ifdef __clang__ #pragma clang diagnostic pop #endif }; struct hresult_access_denied : hresult_error { hresult_access_denied(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, sourceInformation) {} hresult_access_denied(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, message, sourceInformation) {} hresult_access_denied(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi, sourceInformation) {} }; struct hresult_wrong_thread : hresult_error { hresult_wrong_thread(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, sourceInformation) {} hresult_wrong_thread(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, message, sourceInformation) {} hresult_wrong_thread(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi, sourceInformation) {} }; struct hresult_not_implemented : hresult_error { hresult_not_implemented(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, sourceInformation) {} hresult_not_implemented(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, message, sourceInformation) {} hresult_not_implemented(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi, sourceInformation) {} }; struct hresult_invalid_argument : hresult_error { hresult_invalid_argument(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, sourceInformation) {} hresult_invalid_argument(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, message, sourceInformation) {} hresult_invalid_argument(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi, sourceInformation) {} }; struct hresult_out_of_bounds : hresult_error { hresult_out_of_bounds(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, sourceInformation) {} hresult_out_of_bounds(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, message, sourceInformation) {} hresult_out_of_bounds(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi, sourceInformation) {} }; struct hresult_no_interface : hresult_error { hresult_no_interface(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, sourceInformation) {} hresult_no_interface(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, message, sourceInformation) {} hresult_no_interface(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi, sourceInformation) {} }; struct hresult_class_not_available : hresult_error { hresult_class_not_available(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, sourceInformation) {} hresult_class_not_available(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, message, sourceInformation) {} hresult_class_not_available(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi, sourceInformation) {} }; struct hresult_class_not_registered : hresult_error { hresult_class_not_registered(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, sourceInformation) {} hresult_class_not_registered(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, message, sourceInformation) {} hresult_class_not_registered(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi, sourceInformation) {} }; struct hresult_changed_state : hresult_error { hresult_changed_state(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, sourceInformation) {} hresult_changed_state(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, message, sourceInformation) {} hresult_changed_state(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_method_call : hresult_error { hresult_illegal_method_call(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, sourceInformation) {} hresult_illegal_method_call(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, message, sourceInformation) {} hresult_illegal_method_call(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_state_change : hresult_error { hresult_illegal_state_change(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, sourceInformation) {} hresult_illegal_state_change(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, message, sourceInformation) {} hresult_illegal_state_change(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_delegate_assignment : hresult_error { hresult_illegal_delegate_assignment(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, sourceInformation) {} hresult_illegal_delegate_assignment(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message, sourceInformation) {} hresult_illegal_delegate_assignment(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi, sourceInformation) {} }; struct hresult_canceled : hresult_error { hresult_canceled(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, sourceInformation) {} hresult_canceled(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, message, sourceInformation) {} hresult_canceled(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi, sourceInformation) {} }; [[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (winrt_throw_hresult_handler) { winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), result); } if (result == impl::error_bad_alloc) { throw std::bad_alloc(); } if (result == impl::error_access_denied) { throw hresult_access_denied(take_ownership_from_abi, sourceInformation); } if (result == impl::error_wrong_thread) { throw hresult_wrong_thread(take_ownership_from_abi, sourceInformation); } if (result == impl::error_not_implemented) { throw hresult_not_implemented(take_ownership_from_abi, sourceInformation); } if (result == impl::error_invalid_argument) { throw hresult_invalid_argument(take_ownership_from_abi, sourceInformation); } if (result == impl::error_out_of_bounds) { throw hresult_out_of_bounds(take_ownership_from_abi, sourceInformation); } if (result == impl::error_no_interface) { throw hresult_no_interface(take_ownership_from_abi, sourceInformation); } if (result == impl::error_class_not_available) { throw hresult_class_not_available(take_ownership_from_abi, sourceInformation); } if (result == impl::error_class_not_registered) { throw hresult_class_not_registered(take_ownership_from_abi, sourceInformation); } if (result == impl::error_changed_state) { throw hresult_changed_state(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_method_call) { throw hresult_illegal_method_call(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_state_change) { throw hresult_illegal_state_change(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_delegate_assignment) { throw hresult_illegal_delegate_assignment(take_ownership_from_abi, sourceInformation); } if (result == impl::error_canceled) { throw hresult_canceled(take_ownership_from_abi, sourceInformation); } throw hresult_error(result, take_ownership_from_abi, sourceInformation); } inline WINRT_IMPL_NOINLINE hresult to_hresult() noexcept { if (winrt_to_hresult_handler) { return winrt_to_hresult_handler(WINRT_IMPL_RETURNADDRESS()); } try { throw; } catch (hresult_error const& e) { return e.to_abi(); } catch (std::bad_alloc const&) { return impl::error_bad_alloc; } catch (std::out_of_range const& e) { return hresult_out_of_bounds(to_hstring(e.what())).to_abi(); } catch (std::invalid_argument const& e) { return hresult_invalid_argument(to_hstring(e.what())).to_abi(); } catch (std::exception const& e) { return hresult_error(impl::error_fail, to_hstring(e.what())).to_abi(); } } inline WINRT_IMPL_NOINLINE hstring to_message() { if (winrt_to_message_handler) { return winrt_to_message_handler(WINRT_IMPL_RETURNADDRESS()); } try { throw; } catch (hresult_error const& e) { return e.message(); } catch (std::exception const& ex) { return to_hstring(ex.what()); } catch (...) { abort(); } } [[noreturn]] inline void throw_last_error(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError()), sourceInformation); } inline hresult check_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation) { if (result < 0) { throw_hresult(result, sourceInformation); } return result; } template void check_nt(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != 0) { throw_hresult(impl::hresult_from_nt(result), sourceInformation); } } template void check_win32(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != 0) { throw_hresult(impl::hresult_from_win32(result), sourceInformation); } } template T check_bool(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (!result) { winrt::throw_last_error(sourceInformation); } return result; } template T* check_pointer(T* pointer, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (!pointer) { throw_last_error(sourceInformation); } return pointer; } [[noreturn]] inline void terminate() noexcept { WINRT_IMPL_RoFailFastWithErrorContext(to_hresult()); abort(); } } namespace winrt::impl { inline hresult check_hresult_allow_bounds(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != impl::error_out_of_bounds && result != impl::error_fail && result != impl::error_file_not_found) { check_hresult(result, sourceInformation); } return result; } } #undef WINRT_IMPL_RETURNADDRESS namespace winrt::impl { inline int32_t make_marshaler(unknown_abi* outer, void** result) noexcept { struct marshaler final : IMarshal { marshaler(unknown_abi* object) noexcept { m_object.copy_from(object); } int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id)) { *object = static_cast(this); AddRef(); return 0; } return m_object->QueryInterface(id, object); } uint32_t __stdcall AddRef() noexcept final { return ++m_references; } uint32_t __stdcall Release() noexcept final { auto const remaining = --m_references; if (remaining == 0) { delete this; } return remaining; } int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept final { if (m_marshaler) { return m_marshaler->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext, mshlflags, pCid); } return error_bad_alloc; } int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept final { if (m_marshaler) { return m_marshaler->GetMarshalSizeMax(riid, pv, dwDestContext, pvDestContext, mshlflags, pSize); } return error_bad_alloc; } int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept final { if (m_marshaler) { return m_marshaler->MarshalInterface(pStm, riid, pv, dwDestContext, pvDestContext, mshlflags); } return error_bad_alloc; } int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final { if (m_marshaler) { return m_marshaler->UnmarshalInterface(pStm, riid, ppv); } *ppv = nullptr; return error_bad_alloc; } int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final { if (m_marshaler) { return m_marshaler->ReleaseMarshalData(pStm); } return error_bad_alloc; } int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept final { if (m_marshaler) { return m_marshaler->DisconnectObject(dwReserved); } return error_bad_alloc; } private: static com_ptr get_marshaler() noexcept { com_ptr unknown; WINRT_VERIFY_(0, WINRT_IMPL_CoCreateFreeThreadedMarshaler(nullptr, unknown.put_void())); return unknown ? unknown.try_as() : nullptr; } com_ptr m_object; com_ptr m_marshaler{ get_marshaler() }; atomic_ref_count m_references{ 1 }; }; *result = new (std::nothrow) marshaler(outer); return *result ? error_ok : error_bad_alloc; } } namespace winrt::impl { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4458) // declaration hides class member (okay because we do not use named members of base class) #endif struct implements_delegate_base { WINRT_IMPL_NOINLINE uint32_t increment_reference() noexcept { return ++m_references; } WINRT_IMPL_NOINLINE uint32_t decrement_reference() noexcept { return --m_references; } WINRT_IMPL_NOINLINE uint32_t query_interface(guid const& id, void** result, unknown_abi* derivedAbiPtr, guid const& derivedId) noexcept { if (id == derivedId || is_guid_of(id) || is_guid_of(id)) { *result = derivedAbiPtr; increment_reference(); return 0; } if (is_guid_of(id)) { return make_marshaler(derivedAbiPtr, result); } *result = nullptr; return error_no_interface; } private: atomic_ref_count m_references{ 1 }; }; template struct implements_delegate : abi_t, implements_delegate_base, H, update_module_lock { implements_delegate(H&& handler) : H(std::forward(handler)) { } int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { return query_interface(id, result, static_cast*>(this), guid_of()); } uint32_t __stdcall AddRef() noexcept final { return increment_reference(); } uint32_t __stdcall Release() noexcept final { auto const remaining = decrement_reference(); if (remaining == 0) { delete static_cast*>(this); } return remaining; } }; template T make_delegate(H&& handler) { return { static_cast(static_cast*>(new delegate(std::forward(handler)))), take_ownership_from_abi }; } template T make_agile_delegate(T const& delegate) noexcept { if constexpr (!has_category_v) { return delegate; } else { if (delegate.template try_as()) { return delegate; } const auto id = guid_of(); com_ptr ref; get_agile_reference(id, get_abi(delegate), ref.put_void()); if (ref) { return [ref = std::move(ref), id](auto&& ... args) { T delegate; ref->Resolve(id, put_abi(delegate)); return delegate(args...); }; } return delegate; } } template struct WINRT_IMPL_NOVTABLE variadic_delegate_abi : unknown_abi { virtual R invoke(Args const& ...) = 0; }; template struct variadic_delegate final : variadic_delegate_abi, implements_delegate_base, H, update_module_lock { variadic_delegate(H&& handler) : H(std::forward(handler)) { } R invoke(Args const& ... args) final { if constexpr (std::is_void_v) { (*this)(args...); } else { return (*this)(args...); } } int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { return query_interface(id, result, static_cast(this), guid_of()); } uint32_t __stdcall AddRef() noexcept final { return increment_reference(); } uint32_t __stdcall Release() noexcept final { auto const remaining = decrement_reference(); if (remaining == 0) { delete this; } return remaining; } }; template struct WINRT_IMPL_EMPTY_BASES delegate_base : Windows::Foundation::IUnknown { delegate_base(std::nullptr_t = nullptr) noexcept {} delegate_base(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} template delegate_base(L handler) : delegate_base(make(std::forward(handler))) {} template delegate_base(F* handler) : delegate_base([=](auto&& ... args) { return handler(args...); }) {} template delegate_base(O* object, M method) : delegate_base([=](auto&& ... args) { return ((*object).*(method))(args...); }) {} template delegate_base(com_ptr&& object, M method) : delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); }) { } template delegate_base(winrt::weak_ref&& object, LM&& lambda_or_method) : delegate_base([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.get()) { if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); else lm(args...); }}) { } template delegate_base(std::shared_ptr&& object, M method) : delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); }) { } template delegate_base(std::weak_ptr&& object, LM&& lambda_or_method) : delegate_base([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.lock()) { if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); else lm(args...); }}) { } auto operator()(Args const& ... args) const { return (*(variadic_delegate_abi * *)this)->invoke(args...); } private: template static delegate_base make(H&& handler) { return { static_cast(new variadic_delegate(std::forward(handler))), take_ownership_from_abi }; } }; #if defined(_MSC_VER) #pragma warning(pop) #endif } WINRT_EXPORT namespace winrt { template struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; template struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; } WINRT_EXPORT namespace winrt { struct event_token { int64_t value{}; explicit operator bool() const noexcept { return value != 0; } }; inline bool operator==(event_token const& left, event_token const& right) noexcept { return left.value == right.value; } struct auto_revoke_t {}; inline constexpr auto_revoke_t auto_revoke{}; template struct event_revoker { using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); event_revoker() noexcept = default; event_revoker(event_revoker const&) = delete; event_revoker& operator=(event_revoker const&) = delete; event_revoker(event_revoker&&) noexcept = default; event_revoker& operator=(event_revoker&& other) noexcept { if (this != &other) { revoke(); m_object = std::move(other.m_object); m_method = other.m_method; m_token = other.m_token; } return *this; } template event_revoker(U&& object, method_type method, event_token token) : m_object(std::forward(object)), m_method(method), m_token(token) {} ~event_revoker() noexcept { revoke(); } void revoke() noexcept { if (I object = std::exchange(m_object, {}).get()) { ((*reinterpret_cast**>(&object))->*(m_method))(m_token); } } explicit operator bool() const noexcept { return m_object ? true : false; } private: weak_ref m_object; method_type m_method{}; event_token m_token{}; }; template struct factory_event_revoker { using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); factory_event_revoker() noexcept = default; factory_event_revoker(factory_event_revoker const&) = delete; factory_event_revoker& operator=(factory_event_revoker const&) = delete; factory_event_revoker(factory_event_revoker&&) noexcept = default; factory_event_revoker& operator=(factory_event_revoker&& other) noexcept { if (this != &other) { revoke(); m_object = std::move(other.m_object); m_method = other.m_method; m_token = other.m_token; } return *this; } template factory_event_revoker(U&& object, method_type method, event_token token) noexcept : m_object(std::forward(object)), m_method(method), m_token(token) {} ~factory_event_revoker() noexcept { revoke(); } void revoke() noexcept { if (auto object = std::exchange(m_object, {})) { ((*reinterpret_cast**>(&object))->*(m_method))(m_token); } } explicit operator bool() const noexcept { return m_object ? true : false; } private: I m_object; method_type m_method{}; event_token m_token{}; }; } namespace winrt::impl { template struct event_revoker { event_revoker() noexcept = default; event_revoker(event_revoker const&) = delete; event_revoker& operator=(event_revoker const&) = delete; event_revoker(event_revoker&&) noexcept = default; event_revoker& operator=(event_revoker&& other) noexcept { event_revoker(std::move(other)).swap(*this); return *this; } event_revoker(I const& object, event_token token) : m_object(object) , m_token(token) {} operator winrt::event_revoker() && noexcept { return { std::move(m_object), Method, m_token }; } ~event_revoker() noexcept { if (m_object) { revoke_impl(m_object.get()); } } void swap(event_revoker& other) noexcept { std::swap(m_object, other.m_object); std::swap(m_token, other.m_token); } void revoke() noexcept { revoke_impl(std::exchange(m_object, {}).get()); } explicit operator bool() const noexcept { return bool{ m_object }; } private: void revoke_impl(I object) noexcept { if (object) { ((*reinterpret_cast**>(&object))->*(Method))(m_token); } } winrt::weak_ref m_object{}; event_token m_token{}; }; template struct factory_event_revoker { factory_event_revoker() noexcept = default; factory_event_revoker(factory_event_revoker const&) = delete; factory_event_revoker& operator=(factory_event_revoker const&) = delete; factory_event_revoker(factory_event_revoker&&) noexcept = default; factory_event_revoker& operator=(factory_event_revoker&& other) noexcept { factory_event_revoker(std::move(other)).swap(*this); return *this; } factory_event_revoker(I const& object, event_token token) : m_object(object) , m_token(token) {} operator winrt::factory_event_revoker() && noexcept { return { std::move(m_object), Method, m_token }; } ~factory_event_revoker() noexcept { if (m_object) { revoke_impl(m_object); } } void swap(factory_event_revoker& other) noexcept { std::swap(m_object, other.m_object); std::swap(m_token, other.m_token); } void revoke() noexcept { revoke_impl(std::exchange(m_object, {})); } explicit operator bool() const noexcept { return bool{ m_object }; } private: void revoke_impl(I object) noexcept { if (object) { ((*reinterpret_cast**>(&object))->*(Method))(m_token); } } private: I m_object; event_token m_token{}; }; template Revoker make_event_revoker(S source, event_token token) { return { static_cast(*source), token }; } template struct event_array { using value_type = T; using reference = value_type&; using pointer = value_type*; using iterator = value_type*; explicit event_array(uint32_t const count) noexcept : m_size(count) { std::uninitialized_fill_n(data(), count, value_type()); } unsigned long AddRef() noexcept { return ++m_references; } unsigned long Release() noexcept { auto const remaining = --m_references; if (remaining == 0) { this->~event_array(); ::operator delete(static_cast(this)); } return remaining; } reference back() noexcept { WINRT_ASSERT(m_size > 0); return*(data() + m_size - 1); } iterator begin() noexcept { return data(); } iterator end() noexcept { return data() + m_size; } uint32_t size() const noexcept { return m_size; } ~event_array() noexcept { std::destroy(begin(), end()); } private: pointer data() noexcept { return reinterpret_cast(this + 1); } atomic_ref_count m_references{ 1 }; uint32_t m_size{ 0 }; }; template com_ptr> make_event_array(uint32_t const capacity) { void* raw = ::operator new(sizeof(event_array) + (sizeof(T)* capacity)); #ifdef _MSC_VER #pragma warning(suppress: 6386) #endif return { new(raw) event_array(capacity), take_ownership_from_abi }; } WINRT_IMPL_NOINLINE inline bool report_failed_invoke() { int32_t const code = to_hresult(); WINRT_IMPL_RoTransformError(code, 0, nullptr); if (code == static_cast(0x80010108) || // RPC_E_DISCONNECTED code == static_cast(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) code == static_cast(0x89020001)) // JSCRIPT_E_CANTEXECUTE { return false; } return true; } template bool invoke(Delegate const& delegate, Arg const&... args) noexcept { try { delegate(args...); } catch (...) { return report_failed_invoke(); } return true; } } WINRT_EXPORT namespace winrt { template struct event { using delegate_type = Delegate; event() = default; event(event const&) = delete; event& operator =(event const&) = delete; explicit operator bool() const noexcept { return m_targets != nullptr; } event_token add(delegate_type const& delegate) { return add_agile(impl::make_agile_delegate(delegate)); } void remove(event_token const token) { // Extends life of old targets array to release delegates outside of lock. delegate_array temp_targets; { slim_lock_guard const change_guard(m_change); if (!m_targets) { return; } uint32_t available_slots = m_targets->size() - 1; delegate_array new_targets; bool removed = false; if (available_slots == 0) { if (get_token(*m_targets->begin()) == token) { removed = true; } } else { new_targets = impl::make_event_array(available_slots); auto new_iterator = new_targets->begin(); for (delegate_type const& element : *m_targets) { if (!removed && token == get_token(element)) { removed = true; continue; } if (available_slots == 0) { WINRT_ASSERT(!removed); break; } *new_iterator = element; ++new_iterator; --available_slots; } } if (removed) { slim_lock_guard const swap_guard(m_swap); temp_targets = std::exchange(m_targets, std::move(new_targets)); } } } void clear() { // Extends life of old targets array to release delegates outside of lock. delegate_array temp_targets; { slim_lock_guard const change_guard(m_change); if (!m_targets) { return; } slim_lock_guard const swap_guard(m_swap); temp_targets = std::exchange(m_targets, nullptr); } } template void operator()(Arg const&... args) { delegate_array temp_targets; { slim_lock_guard const swap_guard(m_swap); temp_targets = m_targets; } if (temp_targets) { for (delegate_type const& element : *temp_targets) { if (!impl::invoke(element, args...)) { remove(get_token(element)); } } } } private: WINRT_IMPL_NOINLINE event_token add_agile(delegate_type delegate) { event_token token{}; // Extends life of old targets array to release delegates outside of lock. delegate_array temp_targets; { slim_lock_guard const change_guard(m_change); delegate_array new_targets = impl::make_event_array((!m_targets) ? 1 : m_targets->size() + 1); if (m_targets) { std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin()); } new_targets->back() = std::move(delegate); token = get_token(new_targets->back()); slim_lock_guard const swap_guard(m_swap); temp_targets = std::exchange(m_targets, std::move(new_targets)); } return token; } event_token get_token(delegate_type const& delegate) const noexcept { return event_token{ reinterpret_cast(WINRT_IMPL_EncodePointer(get_abi(delegate))) }; } using delegate_array = com_ptr>; delegate_array m_targets; slim_mutex m_swap; slim_mutex m_change; }; } namespace winrt::impl { struct library_traits { using type = void*; static void close(type value) noexcept { WINRT_IMPL_FreeLibrary(value); } static constexpr type invalid() noexcept { return nullptr; } }; using library_handle = handle_type; template WINRT_IMPL_NOINLINE hresult get_runtime_activation_factory_impl(param::hstring const& name, winrt::guid const& guid, void** result) noexcept { if (winrt_activation_handler) { return winrt_activation_handler(*(void**)(&name), guid, result); } hresult hr = WINRT_IMPL_RoGetActivationFactory(*(void**)(&name), guid, result); if (hr == impl::error_not_initialized) { auto usage = reinterpret_cast(WINRT_IMPL_GetProcAddress(load_library(L"combase.dll"), "CoIncrementMTAUsage")); if (!usage) { return hr; } void* cookie; usage(&cookie); hr = WINRT_IMPL_RoGetActivationFactory(*(void**)(&name), guid, result); } if (hr == 0) { return 0; } com_ptr error_info; WINRT_IMPL_GetErrorInfo(0, error_info.put_void()); std::wstring path{ static_cast(name) }; std::size_t count{}; while (std::wstring::npos != (count = path.rfind('.'))) { path.resize(count); path += L".dll"; library_handle library(load_library(path.c_str())); path.resize(path.size() - 4); if (!library) { continue; } auto library_call = reinterpret_cast(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory")); if (!library_call) { continue; } com_ptr> library_factory; if (0 != library_call(*(void**)(&name), library_factory.put_void())) { continue; } if constexpr (isSameInterfaceAsIActivationFactory) { *result = library_factory.detach(); library.detach(); return 0; } else if (0 == library_factory.as(guid, result)) { library.detach(); return 0; } } WINRT_IMPL_SetErrorInfo(0, error_info.get()); return hr; } template hresult get_runtime_activation_factory(param::hstring const& name, void** result) noexcept { return get_runtime_activation_factory_impl>(name, guid_of(), result); } } WINRT_EXPORT namespace winrt { template impl::com_ref get_activation_factory(param::hstring const& name) { void* result{}; check_hresult(impl::get_runtime_activation_factory(name, &result)); return { result, take_ownership_from_abi }; } } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif #if defined(__GNUC__) && defined(__aarch64__) #define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER __asm__ __volatile__ ("dmb ish"); #elif defined _M_ARM64 #define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH)); #endif namespace winrt::impl { inline int32_t interlocked_read_32(int32_t const volatile* target) noexcept { #if defined _M_IX86 || defined _M_X64 int32_t const result = *target; _ReadWriteBarrier(); return result; #elif defined _M_ARM64 #if defined(__GNUC__) int32_t const result = *target; #else int32_t const result = __iso_volatile_load32(reinterpret_cast(target)); #endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; #else #error Unsupported architecture #endif } #if defined _WIN64 inline int64_t interlocked_read_64(int64_t const volatile* target) noexcept { #if defined _M_X64 int64_t const result = *target; _ReadWriteBarrier(); return result; #elif defined _M_ARM64 #if defined(__GNUC__) int64_t const result = *target; #else int64_t const result = __iso_volatile_load64(target); #endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; #else #error Unsupported architecture #endif } #endif #undef WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER #ifdef __clang__ #pragma clang diagnostic pop #endif template T* interlocked_read_pointer(T* const volatile* target) noexcept { #ifdef _WIN64 return (T*)interlocked_read_64((int64_t*)target); #else return (T*)interlocked_read_32((int32_t*)target); #endif } #ifdef _WIN64 inline constexpr uint32_t memory_allocation_alignment{ 16 }; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4324) // structure was padded due to alignment specifier #endif struct alignas(16) slist_entry { slist_entry* next; }; union alignas(16) slist_header { struct { uint64_t reserved1; uint64_t reserved2; } reserved1; struct { uint64_t reserved1 : 16; uint64_t reserved2 : 48; uint64_t reserved3 : 4; uint64_t reserved4 : 60; } reserved2; }; #ifdef _MSC_VER #pragma warning(pop) #endif #else inline constexpr uint32_t memory_allocation_alignment{ 8 }; struct slist_entry { slist_entry* next; }; union slist_header { uint64_t reserved1; struct { slist_entry reserved1; uint16_t reserved2; uint16_t reserved3; } reserved2; }; #endif struct factory_count_guard { factory_count_guard(factory_count_guard const&) = delete; factory_count_guard& operator=(factory_count_guard const&) = delete; explicit factory_count_guard(size_t& count) noexcept : m_count(count) { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 _InterlockedIncrement64((int64_t*)&m_count); #else _InterlockedIncrement((long*)&m_count); #endif #endif } ~factory_count_guard() noexcept { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 _InterlockedDecrement64((int64_t*)&m_count); #else _InterlockedDecrement((long*)&m_count); #endif #endif } private: size_t& m_count; }; struct factory_cache_entry_base { struct alignas(sizeof(void*) * 2) object_and_count { unknown_abi* object; size_t count; }; object_and_count m_value; alignas(memory_allocation_alignment) slist_entry m_next; void clear() noexcept { unknown_abi* pointer_value = interlocked_read_pointer(&m_value.object); if (pointer_value == nullptr) { return; } object_and_count current_value{ pointer_value, 0 }; #if defined _WIN64 #if defined(__GNUC__) bool exchanged = __sync_bool_compare_and_swap((__int128*)this, *(__int128*)¤t_value, (__int128)0); #else bool exchanged = 1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)¤t_value); #endif if (exchanged) { pointer_value->Release(); } #else int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)¤t_value); if (result == *(int64_t*)¤t_value) { pointer_value->Release(); } #endif } }; static_assert(std::is_standard_layout_v); #if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM64 #error Unsupported architecture: verify that zero-initialization of SLIST_HEADER is still safe #endif struct factory_cache { factory_cache(factory_cache const&) = delete; factory_cache& operator=(factory_cache const&) = delete; factory_cache() noexcept = default; void add(factory_cache_entry_base* const entry) noexcept { WINRT_ASSERT(entry); WINRT_IMPL_InterlockedPushEntrySList(&m_list, &entry->m_next); } void clear() noexcept { slist_entry* entry = static_cast(WINRT_IMPL_InterlockedFlushSList(&m_list)); while (entry != nullptr) { // entry->next must be read before entry->clear() is called since the InterlockedCompareExchange // inside clear() will allow another thread to add the entry back to the cache. slist_entry* next = entry->next; reinterpret_cast(reinterpret_cast(entry) - offsetof(factory_cache_entry_base, m_next))->clear(); entry = next; } } private: alignas(memory_allocation_alignment) slist_header m_list; }; inline factory_cache& get_factory_cache() noexcept { static factory_cache cache; return cache; } template struct factory_cache_entry : factory_cache_entry_base { template WINRT_IMPL_NOINLINE auto call(F&& callback) { #ifdef WINRT_DIAGNOSTICS get_diagnostics_info().add_factory(); #endif auto object = get_activation_factory(name_of()); if (!object.template try_as()) { #ifdef WINRT_DIAGNOSTICS get_diagnostics_info().non_agile_factory(); #endif return callback(object); } { factory_count_guard const guard(m_value.count); if (nullptr == _InterlockedCompareExchangePointer(reinterpret_cast(&m_value.object), *reinterpret_cast(&object), nullptr)) { *reinterpret_cast(&object) = nullptr; #ifndef WINRT_NO_MODULE_LOCK get_factory_cache().add(this); #endif } return callback(*reinterpret_cast const*>(&m_value.object)); } } }; template factory_cache_entry factory_cache_entry_v{}; template auto call_factory(F&& callback) { auto& factory = factory_cache_entry_v; { factory_count_guard const guard(factory.m_value.count); if (factory.m_value.object) { return callback(*reinterpret_cast const*>(&factory.m_value.object)); } } return factory.call(callback); } template auto call_factory_cast(F&& callback) { auto& factory = factory_cache_entry_v; { factory_count_guard const guard(factory.m_value.count); if (factory.m_value.object) { return callback(*reinterpret_cast const*>(&factory.m_value.object)); } } return factory.call(static_cast(callback)); } template com_ref try_get_activation_factory(param::hstring const& name, hresult_error* exception = nullptr) noexcept { void* result{}; hresult const hr = get_runtime_activation_factory(name, &result); if (hr < 0) { // Ensure that the IRestrictedErrorInfo is not left on the thread. hresult_error local_exception{ hr, take_ownership_from_abi }; if (exception) { // Optionally transfer ownership to the caller. *exception = std::move(local_exception); } } return { result, take_ownership_from_abi }; } template struct produce : produce_base { int32_t __stdcall ActivateInstance(void** instance) noexcept final try { *instance = nullptr; typename D::abi_guard guard(this->shim()); *instance = detach_abi(this->shim().ActivateInstance()); return 0; } catch (...) { return to_hresult(); } }; } WINRT_EXPORT namespace winrt { enum class apartment_type : int32_t { multi_threaded = 0, single_threaded = 2, }; inline void init_apartment(apartment_type const type = apartment_type::multi_threaded) { hresult const result = WINRT_IMPL_CoInitializeEx(nullptr, static_cast(type)); if (result < 0) { throw_hresult(result); } } inline void uninit_apartment() noexcept { WINRT_IMPL_CoUninitialize(); } template auto get_activation_factory() { // Normally, the callback avoids having to return a ref-counted object and the resulting AddRef/Release bump. // In this case we do want a unique reference, so we use the lambda to return one and thus produce an // AddRef'd object that is returned to the caller. return impl::call_factory([](auto&& factory) { return factory; }); } template auto try_get_activation_factory() noexcept { return impl::try_get_activation_factory(name_of()); } template auto try_get_activation_factory(hresult_error& exception) noexcept { return impl::try_get_activation_factory(name_of(), &exception); } template auto try_get_activation_factory(param::hstring const& name) noexcept { return impl::try_get_activation_factory(name); } template auto try_get_activation_factory(param::hstring const& name, hresult_error& exception) noexcept { return impl::try_get_activation_factory(name, &exception); } inline void clear_factory_cache() noexcept { impl::get_factory_cache().clear(); } template auto try_create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return try_capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } template auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } namespace Windows::Foundation { struct IActivationFactory : IInspectable { IActivationFactory(std::nullptr_t = nullptr) noexcept {} IActivationFactory(void* ptr, take_ownership_from_abi_t) noexcept : IInspectable(ptr, take_ownership_from_abi) {} template T ActivateInstance() const { IInspectable instance; check_hresult((*(impl::abi_t**)this)->ActivateInstance(put_abi(instance))); return instance.try_as(); } }; } } namespace winrt::impl { template T fast_activate(Windows::Foundation::IActivationFactory const& factory) { void* result{}; check_hresult((*(impl::abi_t**)&factory)->ActivateInstance(&result)); return{ result, take_ownership_from_abi }; } } #if defined(_MSC_VER) #if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION) #pragma detect_mismatch("C++/WinRT WINRT_NO_MAKE_DETECTION", "make detection enabled (DEBUG and !WINRT_NO_MAKE_DETECTION)") #else #pragma detect_mismatch("C++/WinRT WINRT_NO_MAKE_DETECTION", "make detection disabled (!DEBUG or WINRT_NO_MAKE_DETECTION)") #endif #endif namespace winrt::impl { struct marker { marker() = delete; }; } WINRT_EXPORT namespace winrt { struct non_agile : impl::marker {}; struct no_weak_ref : impl::marker {}; struct composing : impl::marker {}; struct composable : impl::marker {}; struct no_module_lock : impl::marker {}; struct static_lifetime : impl::marker {}; template struct cloaked : Interface {}; template struct implements; } namespace winrt::impl { template using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); template