mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
In Prod LLVM release branch 515643669.1 ( cl/517696539 ) the experimental coroutines implementation is dropped. The `experimental/coroutines` header is removed. Nearby doesn't use coroutines, but it uses libraries that depend on the existence of coroutine function definitions. Specifically, WinRT needs certain coroutine function definitions in order to compile. Ordinarily, WinRT relied on the coroutine function definitions provided in the MSVC STL' `experimental/coroutines` header. The introduction of libc++ complicated this dependency for Nearby, because libc++' `experimental/coroutines` header took the place of the MSVC version, and (correctly, for C++17) provided none of the coroutine function definitions. To resolve these issues, we implemented a patch of WinRT. The patch provided placeholder definitions, which allowed WinRT to pass compilation. This patch was submitted in cl/495104919. The patch was necessary to enable the Nearby migration from MSVC STL to libc++. -- The removal of `experimental/coroutines` from libc++ makes this patch unnecessary. However, the patch will not compile without libc++' `experimental/coroutines` header. The presence of libc++' `experimental/coroutines` header had prevented the corresponding MSVC STL' header from defining the functions for which the patch makes placeholders. Without the libc++' `experimental/coroutines` header, the MSVC STL header is employed and makes these definitions. The patch then redefines these functions, which causes a compilation failure. -- This CL makes two changes: 1) It eliminates the patch, and 2) It eliminates the libc++ `experimental/coroutines` file from the Lexan libc++ distribution. This allows Nearby to function identically before and after the release of Lexan 515643669.1. This change prevents a break from occurring when Lexan 515643669.1 is released. PiperOrigin-RevId: 518119913
9628 lines
289 KiB
C++
9628 lines
289 KiB
C++
// WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.220531.1
|
|
|
|
#define CPPWINRT_VERSION "2.0.220531.1"
|
|
|
|
#pragma once
|
|
#ifndef WINRT_BASE_H
|
|
#define WINRT_BASE_H
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <charconv>
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <iterator>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#if __has_include(<WindowsNumerics.impl.h>)
|
|
#define WINRT_IMPL_NUMERICS
|
|
#include <directxmath.h>
|
|
#endif
|
|
|
|
#ifdef __cpp_lib_format
|
|
#include <format>
|
|
#endif
|
|
|
|
#ifdef __cpp_lib_coroutine
|
|
|
|
#include <coroutine>
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T = void>
|
|
using coroutine_handle = std::coroutine_handle<T>;
|
|
|
|
using suspend_always = std::suspend_always;
|
|
using suspend_never = std::suspend_never;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <experimental/coroutine>
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T = void>
|
|
using coroutine_handle = std::experimental::coroutine_handle<T>;
|
|
|
|
using suspend_always = std::experimental::suspend_always;
|
|
using suspend_never = std::experimental::suspend_never;
|
|
}
|
|
|
|
#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<D const&>(*this)))
|
|
|
|
// 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)
|
|
|
|
#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 <WindowsNumerics.impl.h>
|
|
#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
|
|
|
|
#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
|
|
|
|
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::ratio<100>, std::nano>;
|
|
struct IAgileObject;
|
|
|
|
struct com_callback_args
|
|
{
|
|
uint32_t reserved1;
|
|
uint32_t reserved2;
|
|
void* data;
|
|
};
|
|
|
|
template <typename T>
|
|
constexpr uint8_t hex_to_uint(T const c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
{
|
|
return static_cast<uint8_t>(c - '0');
|
|
}
|
|
else if (c >= 'A' && c <= 'F')
|
|
{
|
|
return static_cast<uint8_t>(10 + c - 'A');
|
|
}
|
|
else if (c >= 'a' && c <= 'f')
|
|
{
|
|
return static_cast<uint8_t>(10 + c - 'a');
|
|
}
|
|
else
|
|
{
|
|
throw std::invalid_argument("Character is not a hexadecimal digit");
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
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<uint16_t>(a) << 8) | static_cast<uint16_t>(b);
|
|
}
|
|
|
|
constexpr uint32_t uint8_to_uint32(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
|
{
|
|
return (static_cast<uint32_t>(uint8_to_uint16(a, b)) << 16) |
|
|
static_cast<uint32_t>(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 <typename TStringView>
|
|
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<uint8_t, 8> 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<bool dummy = true>
|
|
constexpr guid(GUID const& value) noexcept : guid(convert<dummy>(value)) { }
|
|
|
|
operator GUID const&() const noexcept
|
|
{
|
|
return reinterpret_cast<GUID const&>(*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<bool, typename T>
|
|
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<int64_t, impl::filetime_period>;
|
|
using DateTime = std::chrono::time_point<clock, TimeSpan>;
|
|
}
|
|
|
|
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<hresult>(0x80004005) }; // E_FAIL
|
|
inline constexpr hresult error_access_denied{ static_cast<hresult>(0x80070005) }; // E_ACCESSDENIED
|
|
inline constexpr hresult error_wrong_thread{ static_cast<hresult>(0x8001010E) }; // RPC_E_WRONG_THREAD
|
|
inline constexpr hresult error_not_implemented{ static_cast<hresult>(0x80004001) }; // E_NOTIMPL
|
|
inline constexpr hresult error_invalid_argument{ static_cast<hresult>(0x80070057) }; // E_INVALIDARG
|
|
inline constexpr hresult error_out_of_bounds{ static_cast<hresult>(0x8000000B) }; // E_BOUNDS
|
|
inline constexpr hresult error_no_interface{ static_cast<hresult>(0x80004002) }; // E_NOINTERFACE
|
|
inline constexpr hresult error_class_not_available{ static_cast<hresult>(0x80040111) }; // CLASS_E_CLASSNOTAVAILABLE
|
|
inline constexpr hresult error_class_not_registered{ static_cast<hresult>(0x80040154) }; // REGDB_E_CLASSNOTREG
|
|
inline constexpr hresult error_changed_state{ static_cast<hresult>(0x8000000C) }; // E_CHANGED_STATE
|
|
inline constexpr hresult error_illegal_method_call{ static_cast<hresult>(0x8000000E) }; // E_ILLEGAL_METHOD_CALL
|
|
inline constexpr hresult error_illegal_state_change{ static_cast<hresult>(0x8000000D) }; // E_ILLEGAL_STATE_CHANGE
|
|
inline constexpr hresult error_illegal_delegate_assignment{ static_cast<hresult>(0x80000018) }; // E_ILLEGAL_DELEGATE_ASSIGNMENT
|
|
inline constexpr hresult error_canceled{ static_cast<hresult>(0x800704C7) }; // HRESULT_FROM_WIN32(ERROR_CANCELLED)
|
|
inline constexpr hresult error_bad_alloc{ static_cast<hresult>(0x8007000E) }; // E_OUTOFMEMORY
|
|
inline constexpr hresult error_not_initialized{ static_cast<hresult>(0x800401F0) }; // CO_E_NOTINITIALIZED
|
|
inline constexpr hresult error_file_not_found{ static_cast<hresult>(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) void(__stdcall* winrt_suspend_handler)(void const* token) noexcept {};
|
|
__declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {};
|
|
__declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {};
|
|
|
|
extern "C"
|
|
{
|
|
void* __stdcall WINRT_IMPL_LoadLibraryW(wchar_t const* name) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept;
|
|
void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept;
|
|
|
|
int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, uint32_t type) noexcept;
|
|
void __stdcall WINRT_IMPL_CoUninitialize() noexcept;
|
|
|
|
int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept;
|
|
void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept;
|
|
void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept;
|
|
winrt::impl::bstr __stdcall WINRT_IMPL_SysAllocString(wchar_t const* value) noexcept;
|
|
void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept;
|
|
uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept;
|
|
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;
|
|
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;
|
|
void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, uint32_t flags, size_t bytes) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, uint32_t flags, void* value) noexcept;
|
|
void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept;
|
|
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;
|
|
uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept;
|
|
void __stdcall WINRT_IMPL_GetSystemTimePreciseAsFileTime(void* result) noexcept;
|
|
uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, uintptr_t length) noexcept;
|
|
void* __stdcall WINRT_IMPL_EncodePointer(void* ptr) noexcept;
|
|
|
|
int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, uint32_t access, void** token) noexcept;
|
|
void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept;
|
|
int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept;
|
|
void* __stdcall WINRT_IMPL_GetCurrentThread() noexcept;
|
|
int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept;
|
|
|
|
void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
|
|
void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept;
|
|
uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
|
|
uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept;
|
|
void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept;
|
|
void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags) noexcept;
|
|
void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept;
|
|
void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept;
|
|
void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept;
|
|
void* __stdcall WINRT_IMPL_InterlockedFlushSList(void* head) noexcept;
|
|
|
|
void* __stdcall WINRT_IMPL_CreateEventW(void*, int32_t, int32_t, void*) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept;
|
|
uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept;
|
|
|
|
int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept;
|
|
winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept;
|
|
void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept;
|
|
void __stdcall WINRT_IMPL_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept;
|
|
winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept;
|
|
void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept;
|
|
void __stdcall WINRT_IMPL_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept;
|
|
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;
|
|
void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept;
|
|
void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept;
|
|
void __stdcall WINRT_IMPL_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept;
|
|
winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept;
|
|
void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept;
|
|
int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept;
|
|
void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept;
|
|
|
|
int32_t __stdcall WINRT_CanUnloadNow() noexcept;
|
|
int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept;
|
|
}
|
|
|
|
#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
|
|
|
|
WINRT_IMPL_LINK(LoadLibraryW, 4)
|
|
WINRT_IMPL_LINK(FreeLibrary, 4)
|
|
WINRT_IMPL_LINK(GetProcAddress, 8)
|
|
WINRT_IMPL_LINK(SetErrorInfo, 8)
|
|
WINRT_IMPL_LINK(GetErrorInfo, 8)
|
|
WINRT_IMPL_LINK(CoInitializeEx, 8)
|
|
WINRT_IMPL_LINK(CoUninitialize, 0)
|
|
|
|
WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8)
|
|
WINRT_IMPL_LINK(CoCreateInstance, 20)
|
|
WINRT_IMPL_LINK(CoGetCallContext, 8)
|
|
WINRT_IMPL_LINK(CoGetObjectContext, 8)
|
|
WINRT_IMPL_LINK(CoGetApartmentType, 8)
|
|
WINRT_IMPL_LINK(CoTaskMemAlloc, 4)
|
|
WINRT_IMPL_LINK(CoTaskMemFree, 4)
|
|
WINRT_IMPL_LINK(SysAllocString, 4)
|
|
WINRT_IMPL_LINK(SysFreeString, 4)
|
|
WINRT_IMPL_LINK(SysStringLen, 4)
|
|
WINRT_IMPL_LINK(IIDFromString, 8)
|
|
WINRT_IMPL_LINK(MultiByteToWideChar, 24)
|
|
WINRT_IMPL_LINK(WideCharToMultiByte, 32)
|
|
WINRT_IMPL_LINK(HeapAlloc, 12)
|
|
WINRT_IMPL_LINK(HeapFree, 12)
|
|
WINRT_IMPL_LINK(GetProcessHeap, 0)
|
|
WINRT_IMPL_LINK(FormatMessageW, 28)
|
|
WINRT_IMPL_LINK(GetLastError, 0)
|
|
WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4)
|
|
WINRT_IMPL_LINK(VirtualQuery, 12)
|
|
WINRT_IMPL_LINK(EncodePointer, 4)
|
|
|
|
WINRT_IMPL_LINK(OpenProcessToken, 12)
|
|
WINRT_IMPL_LINK(GetCurrentProcess, 0)
|
|
WINRT_IMPL_LINK(DuplicateToken, 12)
|
|
WINRT_IMPL_LINK(OpenThreadToken, 16)
|
|
WINRT_IMPL_LINK(GetCurrentThread, 0)
|
|
WINRT_IMPL_LINK(SetThreadToken, 8)
|
|
|
|
WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4)
|
|
WINRT_IMPL_LINK(AcquireSRWLockShared, 4)
|
|
WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4)
|
|
WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4)
|
|
WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4)
|
|
WINRT_IMPL_LINK(ReleaseSRWLockShared, 4)
|
|
WINRT_IMPL_LINK(SleepConditionVariableSRW, 16)
|
|
WINRT_IMPL_LINK(WakeConditionVariable, 4)
|
|
WINRT_IMPL_LINK(WakeAllConditionVariable, 4)
|
|
WINRT_IMPL_LINK(InterlockedPushEntrySList, 8)
|
|
WINRT_IMPL_LINK(InterlockedFlushSList, 4)
|
|
|
|
WINRT_IMPL_LINK(CreateEventW, 16)
|
|
WINRT_IMPL_LINK(SetEvent, 4)
|
|
WINRT_IMPL_LINK(CloseHandle, 4)
|
|
WINRT_IMPL_LINK(WaitForSingleObject, 8)
|
|
|
|
WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12)
|
|
WINRT_IMPL_LINK(CreateThreadpoolTimer, 12)
|
|
WINRT_IMPL_LINK(SetThreadpoolTimer, 16)
|
|
WINRT_IMPL_LINK(CloseThreadpoolTimer, 4)
|
|
WINRT_IMPL_LINK(CreateThreadpoolWait, 12)
|
|
WINRT_IMPL_LINK(SetThreadpoolWait, 12)
|
|
WINRT_IMPL_LINK(CloseThreadpoolWait, 4)
|
|
WINRT_IMPL_LINK(CreateThreadpoolIo, 16)
|
|
WINRT_IMPL_LINK(StartThreadpoolIo, 4)
|
|
WINRT_IMPL_LINK(CancelThreadpoolIo, 4)
|
|
WINRT_IMPL_LINK(CloseThreadpoolIo, 4)
|
|
WINRT_IMPL_LINK(CreateThreadpool, 4)
|
|
WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8)
|
|
WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8)
|
|
WINRT_IMPL_LINK(CloseThreadpool, 4)
|
|
|
|
#undef WINRT_IMPL_LINK
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
hresult check_hresult(hresult const result);
|
|
hresult to_hresult() noexcept;
|
|
|
|
template <typename D, typename I>
|
|
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 <typename T>
|
|
struct com_ptr;
|
|
|
|
namespace param
|
|
{
|
|
template <typename T>
|
|
struct iterable;
|
|
|
|
template <typename T>
|
|
struct async_iterable;
|
|
|
|
template <typename K, typename V>
|
|
struct map_view;
|
|
|
|
template <typename K, typename V>
|
|
struct async_map_view;
|
|
|
|
template <typename K, typename V>
|
|
struct map;
|
|
|
|
template <typename T>
|
|
struct vector_view;
|
|
|
|
template <typename T>
|
|
struct async_vector_view;
|
|
|
|
template <typename T>
|
|
struct vector;
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
using namespace std::literals;
|
|
|
|
template <typename T>
|
|
struct reference_traits;
|
|
|
|
template <typename T>
|
|
struct identity
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T, typename Enable = void>
|
|
struct abi
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct abi<T, std::enable_if_t<std::is_enum_v<T>>>
|
|
{
|
|
using type = std::underlying_type_t<T>;
|
|
};
|
|
|
|
template <typename T>
|
|
using abi_t = typename abi<T>::type;
|
|
|
|
template <typename T>
|
|
struct consume;
|
|
|
|
template <typename D, typename I = D>
|
|
using consume_t = typename consume<I>::template type<D>;
|
|
|
|
template <typename T, typename H>
|
|
struct delegate;
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct default_interface
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
struct basic_category;
|
|
struct interface_category;
|
|
struct delegate_category;
|
|
struct enum_category;
|
|
struct class_category;
|
|
|
|
template <typename T>
|
|
struct category
|
|
{
|
|
using type = void;
|
|
};
|
|
|
|
template <typename T>
|
|
using category_t = typename category<T>::type;
|
|
|
|
template <typename T>
|
|
inline constexpr bool has_category_v = !std::is_same_v<category_t<T>, void>;
|
|
|
|
template <typename... Args>
|
|
struct generic_category;
|
|
|
|
template <typename... Fields>
|
|
struct struct_category;
|
|
|
|
template <typename Category, typename T>
|
|
struct category_signature;
|
|
|
|
template <typename T>
|
|
struct signature
|
|
{
|
|
static constexpr auto data{ category_signature<category_t<T>, T>::data };
|
|
};
|
|
|
|
template <typename T>
|
|
#if defined(__clang__)
|
|
#if __has_declspec_attribute(uuid)
|
|
inline const guid guid_v{ __uuidof(T) };
|
|
#else
|
|
inline constexpr guid guid_v{};
|
|
#endif
|
|
#elif defined(_MSC_VER)
|
|
inline constexpr guid guid_v{ __uuidof(T) };
|
|
#else
|
|
inline constexpr guid guid_v{};
|
|
#endif
|
|
|
|
template <typename T>
|
|
constexpr auto to_underlying_type(T const value) noexcept
|
|
{
|
|
return static_cast<std::underlying_type_t<T>>(value);
|
|
}
|
|
|
|
template <typename, typename = std::void_t<>>
|
|
struct is_implements : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct is_implements<T, std::void_t<typename T::implements_type>> : std::true_type {};
|
|
|
|
template <typename T>
|
|
inline constexpr bool is_implements_v = is_implements<T>::value;
|
|
|
|
template <typename D, typename I>
|
|
struct require_one : consume_t<D, I>
|
|
{
|
|
operator I() const noexcept
|
|
{
|
|
return static_cast<D const*>(this)->template try_as<I>();
|
|
}
|
|
};
|
|
|
|
template <typename D, typename... I>
|
|
struct __declspec(empty_bases) require : require_one<D, I>...
|
|
{};
|
|
|
|
template <typename D, typename I>
|
|
struct base_one
|
|
{
|
|
operator I() const noexcept
|
|
{
|
|
return static_cast<D const*>(this)->template try_as<I>();
|
|
}
|
|
};
|
|
|
|
template <typename D, typename... I>
|
|
struct __declspec(empty_bases) base : base_one<D, I>...
|
|
{};
|
|
|
|
template <typename T>
|
|
T empty_value() noexcept
|
|
{
|
|
if constexpr (std::is_base_of_v<Windows::Foundation::IUnknown, T>)
|
|
{
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
|
|
template <typename T, typename Enable = void>
|
|
struct arg
|
|
{
|
|
using in = abi_t<T>;
|
|
};
|
|
|
|
template <typename T>
|
|
struct arg<T, std::enable_if_t<std::is_base_of_v<Windows::Foundation::IUnknown, T>>>
|
|
{
|
|
using in = void*;
|
|
};
|
|
|
|
template <typename T>
|
|
using arg_in = typename arg<T>::in;
|
|
|
|
template <typename T>
|
|
using arg_out = arg_in<T>*;
|
|
|
|
template <typename D, typename I, typename Enable = void>
|
|
struct produce_base;
|
|
|
|
template <typename D, typename I>
|
|
struct produce;
|
|
|
|
template <typename D>
|
|
struct produce<D, Windows::Foundation::IInspectable> : produce_base<D, Windows::Foundation::IInspectable>
|
|
{
|
|
};
|
|
|
|
template <typename T>
|
|
struct wrapped_type
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct wrapped_type<com_ptr<T>>
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using wrapped_type_t = typename wrapped_type<T>::type;
|
|
|
|
template <typename ... Types>
|
|
struct typelist {};
|
|
|
|
template <typename ... Lists>
|
|
struct typelist_concat;
|
|
|
|
template <>
|
|
struct typelist_concat<> { using type = winrt::impl::typelist<>; };
|
|
|
|
template <typename ... List>
|
|
struct typelist_concat<winrt::impl::typelist<List...>> { using type = winrt::impl::typelist<List...>; };
|
|
|
|
template <typename ... List1, typename ... List2, typename ... Rest>
|
|
struct typelist_concat<winrt::impl::typelist<List1...>, winrt::impl::typelist<List2...>, Rest...>
|
|
: typelist_concat<winrt::impl::typelist<List1..., List2...>, Rest...>
|
|
{};
|
|
|
|
template <typename T>
|
|
struct for_each;
|
|
|
|
template <typename ... Types>
|
|
struct for_each<typelist<Types...>>
|
|
{
|
|
template <typename Func>
|
|
static auto apply([[maybe_unused]] Func&& func)
|
|
{
|
|
return (func(Types{}), ...);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct find_if;
|
|
|
|
template <typename ... Types>
|
|
struct find_if<typelist<Types...>>
|
|
{
|
|
template <typename Func>
|
|
static bool apply([[maybe_unused]] Func&& func)
|
|
{
|
|
return (func(Types{}) || ...);
|
|
}
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
using default_interface = typename impl::default_interface<T>::type;
|
|
|
|
template <typename T>
|
|
constexpr guid const& guid_of() noexcept
|
|
{
|
|
return impl::guid_v<default_interface<T>>;
|
|
}
|
|
|
|
template <typename... T>
|
|
bool is_guid_of(guid const& id) noexcept
|
|
{
|
|
return ((id == guid_of<T>()) || ...);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <size_t Size, typename T, size_t... Index>
|
|
constexpr std::array<T, Size> to_array(T const* value, std::index_sequence<Index...> const) noexcept
|
|
{
|
|
return { value[Index]... };
|
|
}
|
|
|
|
template <typename T, size_t Size>
|
|
constexpr auto to_array(std::array<T, Size> const& value) noexcept
|
|
{
|
|
return value;
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr auto to_array(char const(&value)[Size]) noexcept
|
|
{
|
|
return to_array<Size - 1>(value, std::make_index_sequence<Size - 1>());
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr auto to_array(wchar_t const(&value)[Size]) noexcept
|
|
{
|
|
return to_array<Size - 1>(value, std::make_index_sequence<Size - 1>());
|
|
}
|
|
|
|
template <typename T, size_t LeftSize, size_t RightSize, size_t... LeftIndex, size_t... RightIndex>
|
|
constexpr std::array<T, LeftSize + RightSize> concat(
|
|
[[maybe_unused]] std::array<T, LeftSize> const& left,
|
|
[[maybe_unused]] std::array<T, RightSize> const& right,
|
|
std::index_sequence<LeftIndex...> const,
|
|
std::index_sequence<RightIndex...> const) noexcept
|
|
{
|
|
return { left[LeftIndex]..., right[RightIndex]... };
|
|
}
|
|
|
|
template <typename T, size_t LeftSize, size_t RightSize>
|
|
constexpr auto concat(std::array<T, LeftSize> const& left, std::array<T, RightSize> const& right) noexcept
|
|
{
|
|
return concat(left, right, std::make_index_sequence<LeftSize>(), std::make_index_sequence<RightSize>());
|
|
}
|
|
|
|
template <typename T, size_t LeftSize, size_t RightSize>
|
|
constexpr auto concat(std::array<T, LeftSize> const& left, T const(&right)[RightSize]) noexcept
|
|
{
|
|
return concat(left, to_array(right));
|
|
}
|
|
|
|
template <typename T, size_t LeftSize, size_t RightSize>
|
|
constexpr auto concat(T const(&left)[LeftSize], std::array<T, RightSize> const& right) noexcept
|
|
{
|
|
return concat(to_array(left), right);
|
|
}
|
|
|
|
template <typename T, size_t LeftSize>
|
|
constexpr auto concat(std::array<T, LeftSize> const& left, T const right) noexcept
|
|
{
|
|
return concat(left, std::array<T, 1>{right});
|
|
}
|
|
|
|
template <typename T, size_t RightSize>
|
|
constexpr auto concat(T const left, std::array<T, RightSize> const& right) noexcept
|
|
{
|
|
return concat(std::array<T, 1>{left}, right);
|
|
}
|
|
|
|
template <typename First, typename... Rest>
|
|
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 <typename T, size_t LS, size_t RS, size_t... LI, size_t... RI>
|
|
constexpr std::array<T, LS + RS - 1> zconcat_base(std::array<T, LS> const& left, std::array<T, RS> const& right, std::index_sequence<LI...> const, std::index_sequence<RI...> const) noexcept
|
|
{
|
|
return { left[LI]..., right[RI]..., T{} };
|
|
}
|
|
|
|
template <typename T, size_t LS, size_t RS>
|
|
constexpr auto zconcat(std::array<T, LS> const& left, std::array<T, RS> const& right) noexcept
|
|
{
|
|
return zconcat_base(left, right, std::make_index_sequence<LS - 1>(), std::make_index_sequence<RS - 1>());
|
|
}
|
|
|
|
template <typename T, size_t S, size_t... I>
|
|
constexpr std::array<T, S> to_zarray_base(T const(&value)[S], std::index_sequence<I...> const) noexcept
|
|
{
|
|
return { value[I]... };
|
|
}
|
|
|
|
template <typename T, size_t S>
|
|
constexpr auto to_zarray(T const(&value)[S]) noexcept
|
|
{
|
|
return to_zarray_base(value, std::make_index_sequence<S>());
|
|
}
|
|
|
|
template <typename T, size_t S>
|
|
constexpr auto to_zarray(std::array<T, S> const& value) noexcept
|
|
{
|
|
return value;
|
|
}
|
|
|
|
template <typename First, typename... Rest>
|
|
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<uint8_t, 4> to_array(uint32_t value) noexcept
|
|
{
|
|
return { static_cast<uint8_t>(value & 0x000000ff), static_cast<uint8_t>((value & 0x0000ff00) >> 8), static_cast<uint8_t>((value & 0x00ff0000) >> 16), static_cast<uint8_t>((value & 0xff000000) >> 24) };
|
|
}
|
|
|
|
constexpr std::array<uint8_t, 2> to_array(uint16_t value) noexcept
|
|
{
|
|
return { static_cast<uint8_t>(value & 0x00ff), static_cast<uint8_t>((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<uint8_t, 8>{ 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 <typename T>
|
|
constexpr T to_hex_digit(uint8_t value) noexcept
|
|
{
|
|
value &= 0xF;
|
|
return value < 10 ? static_cast<T>('0') + value : static_cast<T>('a') + (value - 10);
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr std::array<T, 2> uint8_to_hex(uint8_t const value) noexcept
|
|
{
|
|
return { to_hex_digit<T>(value >> 4), to_hex_digit<T>(value & 0xF) };
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr auto uint16_to_hex(uint16_t value) noexcept
|
|
{
|
|
return combine(uint8_to_hex<T>(static_cast<uint8_t>(value >> 8)), uint8_to_hex<T>(value & 0xFF));
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr auto uint32_to_hex(uint32_t const value) noexcept
|
|
{
|
|
return combine(uint16_to_hex<T>(value >> 16), uint16_to_hex<T>(value & 0xFFFF));
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr auto to_array(guid const& value) noexcept
|
|
{
|
|
return combine
|
|
(
|
|
std::array<T, 1>{'{'},
|
|
uint32_to_hex<T>(value.Data1), std::array<T, 1>{'-'},
|
|
uint16_to_hex<T>(value.Data2), std::array<T, 1>{'-'},
|
|
uint16_to_hex<T>(value.Data3), std::array<T, 1>{'-'},
|
|
uint16_to_hex<T>(value.Data4[0] << 8 | value.Data4[1]), std::array<T, 1>{'-'},
|
|
uint16_to_hex<T>(value.Data4[2] << 8 | value.Data4[3]),
|
|
uint16_to_hex<T>(value.Data4[4] << 8 | value.Data4[5]),
|
|
uint16_to_hex<T>(value.Data4[6] << 8 | value.Data4[7]),
|
|
std::array<T, 1>{'}'}
|
|
);
|
|
}
|
|
|
|
constexpr uint32_t to_guid(uint8_t a, uint8_t b, uint8_t c, uint8_t d) noexcept
|
|
{
|
|
return (static_cast<uint32_t>(d) << 24) | (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(b) << 8) | static_cast<uint32_t>(a);
|
|
}
|
|
|
|
constexpr uint16_t to_guid(uint8_t a, uint8_t b) noexcept
|
|
{
|
|
return (static_cast<uint32_t>(b) << 8) | static_cast<uint32_t>(a);
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr guid to_guid(std::array<uint8_t, Size> 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<uint16_t>((value.Data3 & 0x0fff) | (5 << 12));
|
|
value.Data4[0] = static_cast<uint8_t>((value.Data4[0] & 0x3f) | 0x80);
|
|
return value;
|
|
}
|
|
|
|
template <typename T, size_t Size, size_t... Index>
|
|
constexpr std::array<uint8_t, Size> char_to_byte_array(std::array<T, Size> const& value, std::index_sequence<Index...> const) noexcept
|
|
{
|
|
return { static_cast<uint8_t>(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<uint32_t, 5> process_msg_block(uint8_t const* input, size_t start_pos, std::array<uint32_t, 5> const& intermediate_hash) noexcept
|
|
{
|
|
uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
|
|
std::array<uint32_t, 80> W = {};
|
|
|
|
size_t t = 0;
|
|
uint32_t temp = 0;
|
|
|
|
for (t = 0; t < 16; t++)
|
|
{
|
|
W[t] = static_cast<uint32_t>(input[start_pos + t * 4]) << 24;
|
|
W[t] = W[t] | static_cast<uint32_t>(input[start_pos + t * 4 + 1]) << 16;
|
|
W[t] = W[t] | static_cast<uint32_t>(input[start_pos + t * 4 + 2]) << 8;
|
|
W[t] = W[t] | static_cast<uint32_t>(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 <size_t Size>
|
|
constexpr std::array<uint32_t, 5> process_msg_block(std::array<uint8_t, Size> const& input, size_t start_pos, std::array<uint32_t, 5> const& intermediate_hash) noexcept
|
|
{
|
|
return process_msg_block(input.data(), start_pos, intermediate_hash);
|
|
}
|
|
|
|
constexpr std::array<uint8_t, 8> size_to_bytes(size_t size) noexcept
|
|
{
|
|
return
|
|
{
|
|
static_cast<uint8_t>((size & 0xff00000000000000) >> 56),
|
|
static_cast<uint8_t>((size & 0x00ff000000000000) >> 48),
|
|
static_cast<uint8_t>((size & 0x0000ff0000000000) >> 40),
|
|
static_cast<uint8_t>((size & 0x000000ff00000000) >> 32),
|
|
static_cast<uint8_t>((size & 0x00000000ff000000) >> 24),
|
|
static_cast<uint8_t>((size & 0x0000000000ff0000) >> 16),
|
|
static_cast<uint8_t>((size & 0x000000000000ff00) >> 8),
|
|
static_cast<uint8_t>((size & 0x00000000000000ff) >> 0)
|
|
};
|
|
}
|
|
|
|
template <size_t Size, size_t RemainingSize, size_t... Index>
|
|
constexpr std::array<uint8_t, RemainingSize + 1> make_remaining([[maybe_unused]] std::array<uint8_t, Size> const& input, [[maybe_unused]] size_t start_pos, std::index_sequence<Index...>) noexcept
|
|
{
|
|
return { input[Index + start_pos]..., 0x80 };
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr auto make_remaining(std::array<uint8_t, Size> const& input, size_t start_pos) noexcept
|
|
{
|
|
constexpr auto remaining_size = Size % 64;
|
|
return make_remaining<Size, remaining_size>(input, start_pos, std::make_index_sequence<remaining_size>());
|
|
}
|
|
|
|
template <size_t InputSize, size_t RemainderSize>
|
|
constexpr auto make_buffer(std::array<uint8_t, RemainderSize> 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<uint8_t, padding_length>{};
|
|
auto length_buffer = size_to_bytes(InputSize * 8);
|
|
|
|
return combine(remaining_buffer, padding_buffer, length_buffer);
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr std::array<uint32_t, 5> finalize_remaining_buffer(std::array<uint8_t, Size> const& input, std::array<uint32_t, 5> 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 <size_t... Index>
|
|
constexpr std::array<uint8_t, 20> get_result(std::array<uint32_t, 5> const& intermediate_hash, std::index_sequence<Index...>) noexcept
|
|
{
|
|
return { static_cast<uint8_t>(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... };
|
|
}
|
|
|
|
constexpr auto get_result(std::array<uint32_t, 5> const& intermediate_hash) noexcept
|
|
{
|
|
return get_result(intermediate_hash, std::make_index_sequence<20>{});
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr auto calculate_sha1(std::array<uint8_t, Size> const& input) noexcept
|
|
{
|
|
std::array<uint32_t, 5> 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<Size>(make_remaining(input, i)), intermediate_hash);
|
|
return get_result(intermediate_hash);
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr guid generate_guid(std::array<char, Size> 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<Size>()));
|
|
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 <typename TArg, typename... TRest>
|
|
struct arg_collection
|
|
{
|
|
constexpr static auto data{ combine(to_array(signature<TArg>::data), ";", arg_collection<TRest...>::data) };
|
|
};
|
|
|
|
template <typename TArg>
|
|
struct arg_collection<TArg>
|
|
{
|
|
constexpr static auto data{ to_array(signature<TArg>::data) };
|
|
};
|
|
|
|
template <typename T>
|
|
struct pinterface_guid
|
|
{
|
|
#pragma warning(suppress: 4307)
|
|
static constexpr guid value{ generate_guid(signature<T>::data) };
|
|
};
|
|
|
|
template <typename T>
|
|
#ifdef __clang__
|
|
inline static const auto name_v
|
|
#else
|
|
#pragma warning(suppress: 4307)
|
|
inline constexpr auto name_v
|
|
#endif
|
|
{
|
|
combine
|
|
(
|
|
to_array<wchar_t>(guid_of<T>()),
|
|
std::array<wchar_t, 1>{ 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<char>(value);
|
|
return 1;
|
|
}
|
|
|
|
if (value <= 0x7FF)
|
|
{
|
|
*buffer = static_cast<char>(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 <typename T>
|
|
constexpr size_t to_utf8_size() noexcept
|
|
{
|
|
auto input = to_array(name_v<T>);
|
|
size_t length = 0;
|
|
|
|
for (wchar_t const element : input)
|
|
{
|
|
length += to_utf8_size(element);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr auto to_utf8() noexcept
|
|
{
|
|
auto input = to_array(name_v<T>);
|
|
std::array<char, to_utf8_size<T>()> output{};
|
|
size_t offset{};
|
|
|
|
for (wchar_t const element : input)
|
|
{
|
|
offset += to_utf8(element, &output[offset]);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr guid generic_guid_v{};
|
|
|
|
template <typename T>
|
|
constexpr auto& basic_signature_v = "";
|
|
|
|
template <> inline constexpr auto& basic_signature_v<bool> = "b1";
|
|
template <> inline constexpr auto& basic_signature_v<int8_t> = "i1";
|
|
template <> inline constexpr auto& basic_signature_v<int16_t> = "i2";
|
|
template <> inline constexpr auto& basic_signature_v<int32_t> = "i4";
|
|
template <> inline constexpr auto& basic_signature_v<int64_t> = "i8";
|
|
template <> inline constexpr auto& basic_signature_v<uint8_t> = "u1";
|
|
template <> inline constexpr auto& basic_signature_v<uint16_t> = "u2";
|
|
template <> inline constexpr auto& basic_signature_v<uint32_t> = "u4";
|
|
template <> inline constexpr auto& basic_signature_v<uint64_t> = "u8";
|
|
template <> inline constexpr auto& basic_signature_v<float> = "f4";
|
|
template <> inline constexpr auto& basic_signature_v<double> = "f8";
|
|
template <> inline constexpr auto& basic_signature_v<char16_t> = "c2";
|
|
template <> inline constexpr auto& basic_signature_v<guid> = "g16";
|
|
template <> inline constexpr auto& basic_signature_v<hstring> = "string";
|
|
template <> inline constexpr auto& basic_signature_v<Windows::Foundation::IInspectable> = "cinterface(IInspectable)";
|
|
|
|
template <> inline constexpr auto& name_v<bool> = L"Boolean";
|
|
template <> inline constexpr auto& name_v<int8_t> = L"Int8";
|
|
template <> inline constexpr auto& name_v<int16_t> = L"Int16";
|
|
template <> inline constexpr auto& name_v<int32_t> = L"Int32";
|
|
template <> inline constexpr auto& name_v<int64_t> = L"Int64";
|
|
template <> inline constexpr auto& name_v<uint8_t> = L"UInt8";
|
|
template <> inline constexpr auto& name_v<uint16_t> = L"UInt16";
|
|
template <> inline constexpr auto& name_v<uint32_t> = L"UInt32";
|
|
template <> inline constexpr auto& name_v<uint64_t> = L"UInt64";
|
|
template <> inline constexpr auto& name_v<float> = L"Single";
|
|
template <> inline constexpr auto& name_v<double> = L"Double";
|
|
template <> inline constexpr auto& name_v<char16_t> = L"Char16";
|
|
template <> inline constexpr auto& name_v<guid> = L"Guid";
|
|
template <> inline constexpr auto& name_v<hstring> = L"String";
|
|
template <> inline constexpr auto& name_v<hresult> = L"Windows.Foundation.HResult";
|
|
template <> inline constexpr auto& name_v<event_token> = L"Windows.Foundation.EventRegistrationToken";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::IInspectable> = L"Object";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::TimeSpan> = L"Windows.Foundation.TimeSpan";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::DateTime> = L"Windows.Foundation.DateTime";
|
|
template <> inline constexpr auto& name_v<IAgileObject> = L"IAgileObject";
|
|
|
|
template <> struct category<bool> { using type = basic_category; };
|
|
template <> struct category<int8_t> { using type = basic_category; };
|
|
template <> struct category<int16_t> { using type = basic_category; };
|
|
template <> struct category<int32_t> { using type = basic_category; };
|
|
template <> struct category<int64_t> { using type = basic_category; };
|
|
template <> struct category<uint8_t> { using type = basic_category; };
|
|
template <> struct category<uint16_t> { using type = basic_category; };
|
|
template <> struct category<uint32_t> { using type = basic_category; };
|
|
template <> struct category<uint64_t> { using type = basic_category; };
|
|
template <> struct category<float> { using type = basic_category; };
|
|
template <> struct category<double> { using type = basic_category; };
|
|
template <> struct category<char16_t> { using type = basic_category; };
|
|
template <> struct category<guid> { using type = basic_category; };
|
|
template <> struct category<hresult> { using type = struct_category<int32_t>; };
|
|
template <> struct category<event_token> { using type = struct_category<int64_t>; };
|
|
template <> struct category<Windows::Foundation::IInspectable> { using type = basic_category; };
|
|
template <> struct category<Windows::Foundation::TimeSpan> { using type = struct_category<int64_t>; };
|
|
template <> struct category<Windows::Foundation::DateTime> { using type = struct_category<int64_t>; };
|
|
|
|
template <typename T>
|
|
struct category_signature<basic_category, T>
|
|
{
|
|
constexpr static auto data{ to_array(basic_signature_v<T>) };
|
|
};
|
|
|
|
template <typename T>
|
|
struct category_signature<enum_category, T>
|
|
{
|
|
using enum_type = std::underlying_type_t<T>;
|
|
constexpr static auto data{ combine("enum(", to_utf8<T>(), ";", signature<enum_type>::data, ")") };
|
|
};
|
|
|
|
template <typename... Fields, typename T>
|
|
struct category_signature<struct_category<Fields...>, T>
|
|
{
|
|
constexpr static auto data{ combine("struct(", to_utf8<T>(), ";", arg_collection<Fields...>::data, ")") };
|
|
};
|
|
|
|
template <typename T>
|
|
struct category_signature<class_category, T>
|
|
{
|
|
constexpr static auto data{ combine("rc(", to_utf8<T>(), ";", signature<winrt::default_interface<T>>::data, ")") };
|
|
};
|
|
|
|
template <typename... Args, typename T>
|
|
struct category_signature<generic_category<Args...>, T>
|
|
{
|
|
constexpr static auto data{ combine("pinterface(", to_array<char>(generic_guid_v<T>), ";", arg_collection<Args...>::data, ")") };
|
|
};
|
|
|
|
template <typename T>
|
|
struct category_signature<interface_category, T>
|
|
{
|
|
constexpr static auto data{ to_array<char>(guid_of<T>()) };
|
|
};
|
|
|
|
template <typename T>
|
|
struct category_signature<delegate_category, T>
|
|
{
|
|
constexpr static auto data{ combine("delegate(", to_array<char>(guid_of<T>()), ")") };
|
|
};
|
|
|
|
template <size_t Size>
|
|
constexpr std::wstring_view to_wstring_view(std::array<wchar_t, Size> const& value) noexcept
|
|
{
|
|
return { value.data(), Size - 1 };
|
|
}
|
|
|
|
template <size_t Size>
|
|
constexpr std::wstring_view to_wstring_view(wchar_t const (&value)[Size]) noexcept
|
|
{
|
|
return { value, Size - 1 };
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
constexpr auto name_of() noexcept
|
|
{
|
|
return impl::to_wstring_view(impl::name_v<T>);
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
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<handle_traits>;
|
|
|
|
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<type>(-1);
|
|
}
|
|
};
|
|
|
|
using file_handle = handle_type<file_handle_traits>;
|
|
}
|
|
|
|
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 <typename T>
|
|
void wait(slim_mutex& x, T predicate)
|
|
{
|
|
while (!predicate())
|
|
{
|
|
WINRT_VERIFY(WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), 0xFFFFFFFF /*INFINITE*/, 0));
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
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<std::chrono::milliseconds>(until - std::chrono::high_resolution_clock::now()).count();
|
|
|
|
if (milliseconds <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast<uint32_t>(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<Windows::Foundation::IUnknown>
|
|
{
|
|
struct __declspec(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<Windows::Foundation::IUnknown>;
|
|
|
|
template <> struct abi<Windows::Foundation::IInspectable>
|
|
{
|
|
struct __declspec(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<Windows::Foundation::IInspectable>;
|
|
|
|
template <> struct abi<Windows::Foundation::IActivationFactory>
|
|
{
|
|
struct __declspec(novtable) type : inspectable_abi
|
|
{
|
|
virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0;
|
|
};
|
|
};
|
|
|
|
struct __declspec(novtable) IAgileObject : unknown_abi {};
|
|
|
|
struct __declspec(novtable) IAgileReference : unknown_abi
|
|
{
|
|
virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0;
|
|
};
|
|
|
|
struct __declspec(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 __declspec(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 __declspec(novtable) IStaticLifetime : inspectable_abi
|
|
{
|
|
virtual int32_t __stdcall unused() noexcept = 0;
|
|
virtual int32_t __stdcall GetCollection(void** value) noexcept = 0;
|
|
};
|
|
|
|
struct __declspec(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 __declspec(novtable) IWeakReference : unknown_abi
|
|
{
|
|
virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0;
|
|
};
|
|
|
|
struct __declspec(novtable) IWeakReferenceSource : unknown_abi
|
|
{
|
|
virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0;
|
|
};
|
|
|
|
struct __declspec(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 __declspec(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 __declspec(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 __declspec(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 __declspec(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 __declspec(novtable) IBufferByteAccess : unknown_abi
|
|
{
|
|
virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0;
|
|
};
|
|
|
|
struct __declspec(novtable) IMemoryBufferByteAccess : unknown_abi
|
|
{
|
|
virtual int32_t __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) noexcept = 0;
|
|
};
|
|
|
|
template <> struct abi<Windows::Foundation::TimeSpan>
|
|
{
|
|
using type = int64_t;
|
|
};
|
|
|
|
template <> struct abi<Windows::Foundation::DateTime>
|
|
{
|
|
using type = int64_t;
|
|
};
|
|
|
|
template <> inline constexpr guid guid_v<Windows::Foundation::IUnknown>{ 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<Windows::Foundation::IInspectable>{ 0xAF86E2E0, 0xB12D, 0x4C6A, { 0x9C,0x5A,0xD7,0xAA,0x65,0x10,0x1E,0x90 } };
|
|
template <> inline constexpr guid guid_v<Windows::Foundation::IActivationFactory>{ 0x00000035, 0x0000, 0x0000, { 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IAgileObject>{ 0x94EA2B94, 0xE9CC, 0x49E0, { 0xC0,0xFF,0xEE,0x64,0xCA,0x8F,0x5B,0x90 } };
|
|
template <> inline constexpr guid guid_v<IAgileReference>{ 0xC03F6A43, 0x65A4, 0x9818, { 0x98,0x7E,0xE0,0xB8,0x10,0xD2,0xA6,0xF2 } };
|
|
template <> inline constexpr guid guid_v<IMarshal>{ 0x00000003, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IGlobalInterfaceTable>{ 0x00000146, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IStaticLifetime>{ 0x17b0e613, 0x942a, 0x422d, { 0x90,0x4c,0xf9,0x0d,0xc7,0x1a,0x7d,0xae } };
|
|
template <> inline constexpr guid guid_v<IStaticLifetimeCollection>{ 0x1b0d3570, 0x0877, 0x5ec2, { 0x8a,0x2c,0x3b,0x95,0x39,0x50,0x6a,0xca } };
|
|
template <> inline constexpr guid guid_v<IWeakReference>{ 0x00000037, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IWeakReferenceSource>{ 0x00000038, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IRestrictedErrorInfo>{ 0x82BA7092, 0x4C88, 0x427D, { 0xA7,0xBC,0x16,0xDD,0x93,0xFE,0xB6,0x7E } };
|
|
template <> inline constexpr guid guid_v<IErrorInfo>{ 0x1CF2B120, 0x547D, 0x101B, { 0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19 } };
|
|
template <> inline constexpr guid guid_v<ILanguageExceptionErrorInfo2>{ 0x5746E5C4, 0x5B97, 0x424C, { 0xB6,0x20,0x28,0x22,0x91,0x57,0x34,0xDD } };
|
|
template <> inline constexpr guid guid_v<ICallbackWithNoReentrancyToApplicationSTA>{ 0x0A299774, 0x3E4E, 0xFC42, { 0x1D,0x9D,0x72,0xCE,0xE1,0x05,0xCA,0x57 } };
|
|
template <> inline constexpr guid guid_v<IContextCallback>{ 0x000001da, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IServerSecurity>{ 0x0000013E, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
template <> inline constexpr guid guid_v<IBufferByteAccess>{ 0x905a0fef, 0xbc53, 0x11df, { 0x8c,0x49,0x00,0x1e,0x4f,0xc6,0x86,0xda } };
|
|
template <> inline constexpr guid guid_v<IMemoryBufferByteAccess>{ 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<std::wstring_view, uint32_t> queries;
|
|
std::map<std::wstring_view, factory_diagnostics_info> factories;
|
|
};
|
|
|
|
struct diagnostics_cache
|
|
{
|
|
template <typename T>
|
|
void add_query()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
++m_info.queries[name_of<T>()];
|
|
}
|
|
|
|
template <typename T>
|
|
void add_factory()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
factory_diagnostics_info& factory = m_info.factories[name_of<T>()];
|
|
++factory.requests;
|
|
}
|
|
|
|
template <typename T>
|
|
void non_agile_factory()
|
|
{
|
|
slim_lock_guard const guard(m_lock);
|
|
factory_diagnostics_info& factory = m_info.factories[name_of<T>()];
|
|
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 <typename T>
|
|
using com_ref = std::conditional_t<std::is_base_of_v<Windows::Foundation::IUnknown, T>, T, com_ptr<T>>;
|
|
|
|
template <typename T, std::enable_if_t<is_implements_v<T>, int> = 0>
|
|
com_ref<T> wrap_as_result(void* result)
|
|
{
|
|
return { &static_cast<produce<T, typename default_interface<T>::type>*>(result)->shim(), take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!is_implements_v<T>, int> = 0>
|
|
com_ref<T> wrap_as_result(void* result)
|
|
{
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
template<typename T>
|
|
struct is_classic_com_interface : std::conjunction<std::is_base_of<::IUnknown, T>, std::negation<is_implements<T>>> {};
|
|
|
|
template <typename T>
|
|
struct is_com_interface : std::disjunction<std::is_base_of<Windows::Foundation::IUnknown, T>, std::is_base_of<unknown_abi, T>, is_implements<T>, is_classic_com_interface<T>> {};
|
|
|
|
template <typename T>
|
|
inline constexpr bool is_com_interface_v = is_com_interface<T>::value;
|
|
|
|
// You must include <winrt/Windows.Foundation.h> to use this overload.
|
|
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
|
|
auto as(From* ptr);
|
|
|
|
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
|
|
com_ref<To> as(From* ptr)
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().add_query<To>();
|
|
#endif
|
|
|
|
if (!ptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void* result{};
|
|
check_hresult(ptr->QueryInterface(guid_of<To>(), &result));
|
|
return wrap_as_result<To>(result);
|
|
}
|
|
|
|
// You must include <winrt/Windows.Foundation.h> to use this overload.
|
|
template <typename To, typename From, std::enable_if_t<!is_com_interface_v<To>, int> = 0>
|
|
auto try_as(From* ptr) noexcept;
|
|
|
|
template <typename To, typename From, std::enable_if_t<is_com_interface_v<To>, int> = 0>
|
|
com_ref<To> try_as(From* ptr) noexcept
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().add_query<To>();
|
|
#endif
|
|
|
|
if (!ptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void* result{};
|
|
ptr->QueryInterface(guid_of<To>(), &result);
|
|
return wrap_as_result<To>(result);
|
|
}
|
|
}
|
|
|
|
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<impl::unknown_abi*>(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 <typename To>
|
|
auto as() const
|
|
{
|
|
return impl::as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
auto try_as() const noexcept
|
|
{
|
|
return impl::try_as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
void as(To& to) const
|
|
{
|
|
to = as<impl::wrapped_type_t<To>>();
|
|
}
|
|
|
|
template <typename To>
|
|
bool try_as(To& to) const noexcept
|
|
{
|
|
if constexpr (impl::is_com_interface_v<To> || !std::is_same_v<To, impl::wrapped_type_t<To>>)
|
|
{
|
|
to = try_as<impl::wrapped_type_t<To>>();
|
|
return static_cast<bool>(to);
|
|
}
|
|
else
|
|
{
|
|
auto result = try_as<To>();
|
|
to = result.has_value() ? result.value() : impl::empty_value<To>();
|
|
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 <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
auto get_abi(T const& object) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<T> const&>(object);
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
auto put_abi(T& object) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
object = {};
|
|
}
|
|
|
|
return reinterpret_cast<impl::abi_t<T>*>(&object);
|
|
}
|
|
|
|
template <typename T, typename V, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
void copy_from_abi(T& object, V&& value)
|
|
{
|
|
object = reinterpret_cast<T const&>(value);
|
|
}
|
|
|
|
template <typename T, typename V, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, T>, int> = 0>
|
|
void copy_to_abi(T const& object, V& value)
|
|
{
|
|
reinterpret_cast<T&>(value) = object;
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!std::is_base_of_v<Windows::Foundation::IUnknown, std::decay_t<T>> && !std::is_convertible_v<T, std::wstring_view>, int> = 0>
|
|
auto detach_abi(T&& object)
|
|
{
|
|
impl::abi_t<T> result{};
|
|
reinterpret_cast<T&>(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<void**>(&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<void**>(&object) = nullptr;
|
|
return temp;
|
|
}
|
|
|
|
inline void* detach_abi(Windows::Foundation::IUnknown&& object) noexcept
|
|
{
|
|
void* temp = get_abi(object);
|
|
*reinterpret_cast<void**>(&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<impl::unknown_abi*>(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<impl::unknown_abi*>(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<IUnknown>()) == get_abi(right.try_as<IUnknown>());
|
|
}
|
|
|
|
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<IUnknown>()) < get_abi(right.try_as<IUnknown>());
|
|
}
|
|
|
|
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 <typename T>
|
|
struct com_ptr;
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T, typename F, typename...Args>
|
|
int32_t capture_to(void**result, F function, Args&& ...args)
|
|
{
|
|
return function(args..., guid_of<T>(), result);
|
|
}
|
|
|
|
template <typename T, typename O, typename M, typename...Args, std::enable_if_t<std::is_class_v<O> || std::is_union_v<O>, int> = 0>
|
|
int32_t capture_to(void** result, O* object, M method, Args&& ...args)
|
|
{
|
|
return (object->*method)(args..., guid_of<T>(), result);
|
|
}
|
|
|
|
template <typename T, typename O, typename M, typename...Args>
|
|
int32_t capture_to(void** result, com_ptr<O> const& object, M method, Args&& ...args);
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
struct com_ptr
|
|
{
|
|
using type = impl::abi_t<T>;
|
|
|
|
com_ptr(std::nullptr_t = nullptr) noexcept {}
|
|
|
|
com_ptr(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast<type*>(ptr))
|
|
{
|
|
}
|
|
|
|
com_ptr(com_ptr const& other) noexcept : m_ptr(other.m_ptr)
|
|
{
|
|
add_ref();
|
|
}
|
|
|
|
template <typename U>
|
|
com_ptr(com_ptr<U> const& other) noexcept : m_ptr(other.m_ptr)
|
|
{
|
|
add_ref();
|
|
}
|
|
|
|
template <typename U>
|
|
com_ptr(com_ptr<U>&& 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 <typename U>
|
|
com_ptr& operator=(com_ptr<U> const& other) noexcept
|
|
{
|
|
copy_ref(other.m_ptr);
|
|
return*this;
|
|
}
|
|
|
|
template <typename U>
|
|
com_ptr& operator=(com_ptr<U>&& 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<void**>(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 <typename To>
|
|
auto as() const
|
|
{
|
|
return impl::as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
auto try_as() const noexcept
|
|
{
|
|
return impl::try_as<To>(m_ptr);
|
|
}
|
|
|
|
template <typename To>
|
|
void as(To& to) const
|
|
{
|
|
to = as<impl::wrapped_type_t<To>>();
|
|
}
|
|
|
|
template <typename To>
|
|
bool try_as(To& to) const noexcept
|
|
{
|
|
if constexpr (impl::is_com_interface_v<To> || !std::is_same_v<To, impl::wrapped_type_t<To>>)
|
|
{
|
|
to = try_as<impl::wrapped_type_t<To>>();
|
|
return static_cast<bool>(to);
|
|
}
|
|
else
|
|
{
|
|
auto result = try_as<To>();
|
|
to = result.has_value() ? result.value() : impl::empty_value<To>();
|
|
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 <typename...Args>
|
|
bool try_capture(Args&&...args)
|
|
{
|
|
return impl::capture_to<T>(put_void(), std::forward<Args>(args)...) >= 0;
|
|
}
|
|
|
|
template <typename...Args>
|
|
void capture(Args&&...args)
|
|
{
|
|
check_hresult(impl::capture_to<T>(put_void(), std::forward<Args>(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<std::remove_const_t<type>*>(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 <typename U>
|
|
friend struct com_ptr;
|
|
|
|
type* m_ptr{};
|
|
};
|
|
|
|
template <typename T, typename...Args>
|
|
impl::com_ref<T> try_capture(Args&& ...args)
|
|
{
|
|
void* result{};
|
|
impl::capture_to<T>(&result, std::forward<Args>(args)...);
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename T, typename...Args>
|
|
impl::com_ref<T> capture(Args&& ...args)
|
|
{
|
|
void* result{};
|
|
check_hresult(impl::capture_to<T>(&result, std::forward<Args>(args)...));
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename T>
|
|
auto get_abi(com_ptr<T> const& object) noexcept
|
|
{
|
|
return object.get();
|
|
}
|
|
|
|
template <typename T>
|
|
auto put_abi(com_ptr<T>& object) noexcept
|
|
{
|
|
return object.put_void();
|
|
}
|
|
|
|
template <typename T>
|
|
void attach_abi(com_ptr<T>& object, impl::abi_t<T>* value) noexcept
|
|
{
|
|
object.attach(value);
|
|
}
|
|
|
|
template <typename T>
|
|
auto detach_abi(com_ptr<T>& object) noexcept
|
|
{
|
|
return object.detach();
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator==(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return get_abi(left) == get_abi(right);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator==(com_ptr<T> const& left, std::nullptr_t) noexcept
|
|
{
|
|
return get_abi(left) == nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator==(std::nullptr_t, com_ptr<T> const& right) noexcept
|
|
{
|
|
return nullptr == get_abi(right);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator!=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator!=(com_ptr<T> const& left, std::nullptr_t) noexcept
|
|
{
|
|
return !(left == nullptr);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator!=(std::nullptr_t, com_ptr<T> const& right) noexcept
|
|
{
|
|
return !(nullptr == right);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator<(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return get_abi(left) < get_abi(right);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator>(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return right < left;
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator<=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return !(right < left);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator>=(com_ptr<T> const& left, com_ptr<T> const& right) noexcept
|
|
{
|
|
return !(left < right);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T, typename O, typename M, typename...Args>
|
|
int32_t capture_to(void** result, com_ptr<O> const& object, M method, Args&& ...args)
|
|
{
|
|
return (object.get()->*(method))(args..., guid_of<T>(), result);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void** IID_PPV_ARGS_Helper(winrt::com_ptr<T>* 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 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 remaining;
|
|
}
|
|
|
|
operator uint32_t() const noexcept
|
|
{
|
|
return m_count;
|
|
}
|
|
|
|
private:
|
|
std::atomic<uint32_t> m_count{0};
|
|
};
|
|
|
|
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<shared_hstring_header*>(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<uint64_t>(sizeof(shared_hstring_header)) + static_cast<uint64_t>(sizeof(wchar_t)) * static_cast<uint64_t>(length);
|
|
|
|
if (bytes_required > UINT_MAX)
|
|
{
|
|
throw std::invalid_argument("length");
|
|
}
|
|
|
|
auto header = static_cast<shared_hstring_header*>(WINRT_IMPL_HeapAlloc(WINRT_IMPL_GetProcessHeap(), 0, static_cast<std::size_t>(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<shared_hstring_header*>(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<const_iterator>;
|
|
|
|
hstring() noexcept = default;
|
|
|
|
hstring(void* ptr, take_ownership_from_abi_t) noexcept : m_handle(static_cast<impl::hstring_header*>(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<wchar_t> value) :
|
|
hstring(value.begin(), static_cast<uint32_t>(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<size_type>(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<wchar_t> 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<impl::hstring_traits> 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<void**>(&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<void**>(&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<impl::hstring_header*>(value)));
|
|
}
|
|
|
|
inline void copy_to_abi(hstring const& object, void*& value)
|
|
{
|
|
WINRT_ASSERT(value == nullptr);
|
|
value = impl::duplicate_hstring(static_cast<impl::hstring_header*>(get_abi(object)));
|
|
}
|
|
|
|
inline void* detach_abi(std::wstring_view const& value)
|
|
{
|
|
return impl::create_hstring_on_heap(value.data(), static_cast<uint32_t>(value.size()));
|
|
}
|
|
|
|
inline void* detach_abi(wchar_t const* const value)
|
|
{
|
|
return impl::create_hstring_on_heap(value, static_cast<uint32_t>(wcslen(value)));
|
|
}
|
|
}
|
|
|
|
#ifdef __cpp_lib_format
|
|
template<>
|
|
struct std::formatter<winrt::hstring, wchar_t> : std::formatter<std::wstring_view, wchar_t> {};
|
|
#endif
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <> struct abi<hstring>
|
|
{
|
|
using type = void*;
|
|
};
|
|
|
|
template <> struct category<hstring>
|
|
{
|
|
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<wchar_t*>(m_handle.get()->ptr);
|
|
}
|
|
|
|
hstring to_hstring()
|
|
{
|
|
return { m_handle.detach(), take_ownership_from_abi };
|
|
}
|
|
|
|
private:
|
|
|
|
handle_type<impl::hstring_traits> m_handle;
|
|
};
|
|
|
|
template <typename T>
|
|
struct bind_in
|
|
{
|
|
bind_in(T const& object) noexcept : object(object)
|
|
{
|
|
}
|
|
|
|
T const& object;
|
|
|
|
template <typename R>
|
|
operator R const& () const noexcept
|
|
{
|
|
return reinterpret_cast<R const&>(object);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct bind_out
|
|
{
|
|
bind_out(T& object) noexcept : object(object)
|
|
{
|
|
}
|
|
|
|
T& object;
|
|
|
|
operator void** () const noexcept
|
|
{
|
|
if constexpr (std::is_same_v<T, hstring>)
|
|
{
|
|
object.clear();
|
|
}
|
|
else
|
|
{
|
|
object = nullptr;
|
|
}
|
|
|
|
return (void**)(&object);
|
|
}
|
|
|
|
template <typename R>
|
|
operator R* () const noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
object = {};
|
|
}
|
|
|
|
return reinterpret_cast<R*>(&object);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inline hstring hstring_convert(T value)
|
|
{
|
|
static_assert(std::is_arithmetic_v<T>);
|
|
char temp[32];
|
|
std::to_chars_result result;
|
|
if constexpr (std::is_integral_v<T>)
|
|
{
|
|
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<std::size_t>(end - buffer)} };
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
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);
|
|
}
|
|
|
|
inline hstring to_hstring(float value)
|
|
{
|
|
return impl::hstring_convert(value);
|
|
}
|
|
|
|
inline hstring to_hstring(double value)
|
|
{
|
|
return impl::hstring_convert(value);
|
|
}
|
|
|
|
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 <typename T, std::enable_if_t<std::is_same_v<T, bool>, 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 <typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view>, 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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(value.size()), result.data(), size, nullptr, nullptr));
|
|
return result;
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt::param
|
|
{
|
|
struct hstring
|
|
{
|
|
#pragma warning(suppress: 26495)
|
|
hstring() noexcept : m_handle(nullptr) {}
|
|
hstring(hstring const& values) = delete;
|
|
hstring& operator=(hstring const& values) = delete;
|
|
hstring(std::nullptr_t) = delete;
|
|
|
|
#pragma warning(suppress: 26495)
|
|
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<winrt::hstring const*>(this);
|
|
}
|
|
|
|
private:
|
|
void create_string_reference(wchar_t const* const data, size_t size) noexcept
|
|
{
|
|
WINRT_ASSERT(size < UINT_MAX);
|
|
auto size32 = static_cast<uint32_t>(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 <typename T>
|
|
using param_type = std::conditional_t<std::is_same_v<T, hstring>, 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, nullptr_t) = delete;
|
|
|
|
bool operator<(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<uint32_t>(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);
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
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<iterator>;
|
|
using const_reverse_iterator = std::reverse_iterator<const_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<size_type>(last - first))
|
|
{}
|
|
|
|
array_view(std::initializer_list<value_type> value) noexcept :
|
|
array_view(value.begin(), static_cast<size_type>(value.size()))
|
|
{}
|
|
|
|
template <typename C, size_type N>
|
|
array_view(C(&value)[N]) noexcept :
|
|
array_view(value, N)
|
|
{}
|
|
|
|
template <typename C>
|
|
array_view(std::vector<C>& value) noexcept :
|
|
array_view(data(value), static_cast<size_type>(value.size()))
|
|
{
|
|
}
|
|
|
|
template <typename C>
|
|
array_view(std::vector<C> const& value) noexcept :
|
|
array_view(data(value), static_cast<size_type>(value.size()))
|
|
{
|
|
}
|
|
|
|
template <typename C, size_t N>
|
|
array_view(std::array<C, N>& value) noexcept :
|
|
array_view(value.data(), static_cast<size_type>(value.size()))
|
|
{}
|
|
|
|
template <typename C, size_t N>
|
|
array_view(std::array<C, N> const& value) noexcept :
|
|
array_view(value.data(), static_cast<size_type>(value.size()))
|
|
{}
|
|
|
|
template <typename OtherType>
|
|
array_view(array_view<OtherType> const& other,
|
|
std::enable_if_t<std::is_convertible_v<OtherType(*)[], 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 <typename C>
|
|
auto data(std::vector<C> const& value) noexcept
|
|
{
|
|
static_assert(!std::is_same_v<C, bool>, "Cannot use std::vector<bool> as an array_view. Consider std::array or std::unique_ptr<bool[]>.");
|
|
return value.data();
|
|
}
|
|
|
|
template <typename C>
|
|
auto data(std::vector<C>& value) noexcept
|
|
{
|
|
static_assert(!std::is_same_v<C, bool>, "Cannot use std::vector<bool> as an array_view. Consider std::array or std::unique_ptr<bool[]>.");
|
|
return value.data();
|
|
}
|
|
};
|
|
|
|
template <typename C, size_t N> array_view(C(&value)[N]) -> array_view<C>;
|
|
template <typename C> array_view(std::vector<C>& value) -> array_view<C>;
|
|
template <typename C> array_view(std::vector<C> const& value) -> array_view<C const>;
|
|
template <typename C, size_t N> array_view(std::array<C, N>& value) -> array_view<C>;
|
|
template <typename C, size_t N> array_view(std::array<C, N> const& value) -> array_view<C const>;
|
|
|
|
template <typename T>
|
|
struct com_array : array_view<T>
|
|
{
|
|
using typename array_view<T>::value_type;
|
|
using typename array_view<T>::size_type;
|
|
using typename array_view<T>::reference;
|
|
using typename array_view<T>::const_reference;
|
|
using typename array_view<T>::pointer;
|
|
using typename array_view<T>::const_pointer;
|
|
using typename array_view<T>::iterator;
|
|
using typename array_view<T>::const_iterator;
|
|
using typename array_view<T>::reverse_iterator;
|
|
using typename array_view<T>::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<T>(static_cast<value_type*>(ptr), static_cast<value_type*>(ptr) + count)
|
|
{
|
|
}
|
|
|
|
com_array(size_type const count, value_type const& value)
|
|
{
|
|
alloc(count);
|
|
std::uninitialized_fill_n(this->m_data, count, value);
|
|
}
|
|
|
|
template <typename InIt, typename = std::void_t<typename std::iterator_traits<InIt>::difference_type>>
|
|
com_array(InIt first, InIt last)
|
|
{
|
|
alloc(static_cast<size_type>(std::distance(first, last)));
|
|
std::uninitialized_copy(first, last, this->begin());
|
|
}
|
|
|
|
template <typename U>
|
|
explicit com_array(std::vector<U> const& value) :
|
|
com_array(value.begin(), value.end())
|
|
{}
|
|
|
|
template <typename U, size_t N>
|
|
explicit com_array(std::array<U, N> const& value) :
|
|
com_array(value.begin(), value.end())
|
|
{}
|
|
|
|
template <typename U, size_t N>
|
|
explicit com_array(U const(&value)[N]) :
|
|
com_array(value, value + N)
|
|
{}
|
|
|
|
com_array(std::initializer_list<value_type> value) :
|
|
com_array(value.begin(), value.end())
|
|
{}
|
|
|
|
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
|
|
com_array(std::initializer_list<U> value) :
|
|
com_array(value.begin(), value.end())
|
|
{}
|
|
|
|
com_array(com_array&& other) noexcept :
|
|
array_view<T>(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<value_type*>(WINRT_IMPL_CoTaskMemAlloc(size * sizeof(value_type)));
|
|
|
|
if (this->m_data == nullptr)
|
|
{
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
this->m_size = size;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename C> com_array(uint32_t, C const&) -> com_array<std::decay_t<C>>;
|
|
template <typename InIt, typename = std::void_t<typename std::iterator_traits<InIt>::difference_type>>
|
|
com_array(InIt, InIt) -> com_array<std::decay_t<typename std::iterator_traits<InIt>::value_type>>;
|
|
template <typename C> com_array(std::vector<C> const&) -> com_array<std::decay_t<C>>;
|
|
template <size_t N, typename C> com_array(std::array<C, N> const&) -> com_array<std::decay_t<C>>;
|
|
template <size_t N, typename C> com_array(C const(&)[N]) -> com_array<std::decay_t<C>>;
|
|
template <typename C> com_array(std::initializer_list<C>) -> com_array<std::decay_t<C>>;
|
|
|
|
namespace impl
|
|
{
|
|
template <typename T, typename U>
|
|
inline constexpr bool array_comparable = std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>;
|
|
}
|
|
|
|
template <typename T, typename U,
|
|
std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator==(array_view<T> const& left, array_view<U> const& right) noexcept
|
|
{
|
|
return std::equal(left.begin(), left.end(), right.begin(), right.end());
|
|
}
|
|
|
|
template <typename T, typename U,
|
|
std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator<(array_view<T> const& left, array_view<U> const& right) noexcept
|
|
{
|
|
return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end());
|
|
}
|
|
|
|
template <typename T, typename U, std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator!=(array_view<T> const& left, array_view<U> const& right) noexcept { return !(left == right); }
|
|
template <typename T, typename U,std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator>(array_view<T> const& left, array_view<U> const& right) noexcept { return right < left; }
|
|
template <typename T, typename U,std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator<=(array_view<T> const& left, array_view<U> const& right) noexcept { return !(right < left); }
|
|
template <typename T, typename U, std::enable_if_t<impl::array_comparable<T, U>, int> = 0>
|
|
bool operator>=(array_view<T> const& left, array_view<U> const& right) noexcept { return !(left < right); }
|
|
|
|
template <typename T>
|
|
auto get_abi(array_view<T> object) noexcept
|
|
{
|
|
auto data = object.size() ? object.data() : (T*)alignof(T);
|
|
|
|
if constexpr (std::is_base_of_v<Windows::Foundation::IUnknown, T>)
|
|
{
|
|
return (void**)data;
|
|
}
|
|
else
|
|
{
|
|
return reinterpret_cast<impl::arg_out<std::remove_const_t<T>>>(const_cast<std::remove_const_t<T>*>(data));
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
auto put_abi(array_view<T> object) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
std::fill(object.begin(), object.end(), impl::empty_value<T>());
|
|
}
|
|
|
|
return get_abi(object);
|
|
}
|
|
|
|
template<typename T>
|
|
auto put_abi(com_array<T>& object) noexcept
|
|
{
|
|
object.clear();
|
|
return reinterpret_cast<impl::arg_out<T>*>(&object);
|
|
}
|
|
|
|
template <typename T>
|
|
auto detach_abi(com_array<T>& object) noexcept
|
|
{
|
|
std::pair<uint32_t, impl::arg_out<T>> result(object.size(), *reinterpret_cast<impl::arg_out<T>*>(&object));
|
|
memset(&object, 0, sizeof(com_array<T>));
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
auto detach_abi(com_array<T>&& object) noexcept
|
|
{
|
|
return detach_abi(object);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T>
|
|
struct array_size_proxy
|
|
{
|
|
array_size_proxy& operator=(array_size_proxy const&) = delete;
|
|
|
|
array_size_proxy(com_array<T>& value) noexcept : m_value(value)
|
|
{}
|
|
|
|
~array_size_proxy() noexcept
|
|
{
|
|
WINRT_ASSERT(m_value.data() || (!m_value.data() && m_size == 0));
|
|
*reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t*>(&m_value) + 1) = m_size;
|
|
}
|
|
|
|
operator uint32_t*() noexcept
|
|
{
|
|
return &m_size;
|
|
}
|
|
|
|
operator unsigned long*() noexcept
|
|
{
|
|
return reinterpret_cast<unsigned long*>(&m_size);
|
|
}
|
|
|
|
private:
|
|
|
|
com_array<T>& m_value;
|
|
uint32_t m_size{ 0 };
|
|
};
|
|
|
|
template<typename T>
|
|
array_size_proxy<T> put_size_abi(com_array<T>& object) noexcept
|
|
{
|
|
return array_size_proxy<T>(object);
|
|
}
|
|
|
|
template <typename T>
|
|
struct com_array_proxy
|
|
{
|
|
com_array_proxy(uint32_t* size, winrt::impl::arg_out<T>* 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<T>&() 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<T>* m_value;
|
|
com_array<T> m_temp;
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
auto detach_abi(uint32_t* __valueSize, impl::arg_out<T>* value) noexcept
|
|
{
|
|
return impl::com_array_proxy<T>(__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<guid> get_interfaces(Windows::Foundation::IInspectable const& object)
|
|
{
|
|
com_array<guid> 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 <typename T>
|
|
struct weak_ref
|
|
{
|
|
weak_ref(std::nullptr_t = nullptr) noexcept {}
|
|
|
|
template<typename U = impl::com_ref<T> const&, typename = std::enable_if_t<std::is_convertible_v<U&&, impl::com_ref<T> const&>>>
|
|
weak_ref(U&& object)
|
|
{
|
|
from_com_ref(static_cast<impl::com_ref<T> const&>(object));
|
|
}
|
|
|
|
[[nodiscard]] auto get() const noexcept
|
|
{
|
|
if (!m_ref)
|
|
{
|
|
return impl::com_ref<T>{ nullptr };
|
|
}
|
|
|
|
if constexpr(impl::is_implements_v<T>)
|
|
{
|
|
impl::com_ref<default_interface<T>> temp;
|
|
m_ref->Resolve(guid_of<T>(), put_abi(temp));
|
|
void* result = get_self<T>(temp);
|
|
detach_abi(temp);
|
|
return impl::com_ref<T>{ result, take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
void* result{};
|
|
m_ref->Resolve(guid_of<T>(), &result);
|
|
return impl::com_ref<T>{ result, take_ownership_from_abi };
|
|
}
|
|
}
|
|
|
|
auto put() noexcept
|
|
{
|
|
return m_ref.put();
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return static_cast<bool>(m_ref);
|
|
}
|
|
|
|
private:
|
|
|
|
template<typename U>
|
|
void from_com_ref(U&& object)
|
|
{
|
|
if (object)
|
|
{
|
|
if constexpr (impl::is_implements_v<T>)
|
|
{
|
|
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<impl::IWeakReferenceSource>()->GetWeakReference(m_ref.put()));
|
|
}
|
|
}
|
|
}
|
|
|
|
com_ptr<impl::IWeakReference> m_ref;
|
|
};
|
|
|
|
template<typename T> weak_ref(T const&)->weak_ref<impl::wrapped_type_t<T>>;
|
|
|
|
template<typename T>
|
|
struct impl::abi<weak_ref<T>> : impl::abi<com_ptr<impl::IWeakReference>>
|
|
{
|
|
};
|
|
|
|
template <typename T>
|
|
inline bool operator==(weak_ref<T> const& left, weak_ref<T> const& right) noexcept
|
|
{
|
|
return get_abi(left) == get_abi(right);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool operator==(weak_ref<T> const& left, std::nullptr_t) noexcept
|
|
{
|
|
return get_abi(left) == nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool operator==(std::nullptr_t, weak_ref<T> const& right) noexcept
|
|
{
|
|
return nullptr == get_abi(right);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool operator!=(weak_ref<T> const& left, weak_ref<T> const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool operator!=(weak_ref<T> const& left, std::nullptr_t) noexcept
|
|
{
|
|
return !(left == nullptr);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool operator!=(std::nullptr_t, weak_ref<T> const& right) noexcept
|
|
{
|
|
return !(nullptr == right);
|
|
}
|
|
|
|
template <typename T>
|
|
weak_ref<impl::wrapped_type_t<T>> 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<bool UseModuleLock>
|
|
struct module_lock_updater;
|
|
|
|
template<>
|
|
struct module_lock_updater<true>
|
|
{
|
|
module_lock_updater() noexcept
|
|
{
|
|
++get_module_lock();
|
|
}
|
|
|
|
~module_lock_updater() noexcept
|
|
{
|
|
--get_module_lock();
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct module_lock_updater<false> {};
|
|
|
|
using update_module_lock = module_lock_updater<true>;
|
|
|
|
struct agile_ref_fallback final : IAgileReference, update_module_lock
|
|
{
|
|
agile_ref_fallback(com_ptr<IGlobalInterfaceTable>&& git, uint32_t cookie) noexcept :
|
|
m_git(std::move(git)),
|
|
m_cookie(cookie)
|
|
{
|
|
}
|
|
|
|
~agile_ref_fallback() noexcept
|
|
{
|
|
m_git->RevokeInterfaceFromGlobal(m_cookie);
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IAgileReference>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = static_cast<IAgileReference*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
*object = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
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 Resolve(guid const& id, void** object) noexcept final
|
|
{
|
|
return m_git->GetInterfaceFromGlobal(m_cookie, id, object);
|
|
}
|
|
|
|
private:
|
|
|
|
com_ptr<IGlobalInterfaceTable> m_git;
|
|
uint32_t m_cookie{};
|
|
atomic_ref_count m_references{ 1 };
|
|
};
|
|
|
|
template <typename F, typename L>
|
|
void load_runtime_function(wchar_t const* library, char const* name, F& result, L fallback) noexcept
|
|
{
|
|
if (result)
|
|
{
|
|
return;
|
|
}
|
|
|
|
result = reinterpret_cast<F>(WINRT_IMPL_GetProcAddress(WINRT_IMPL_LoadLibraryW(library), name));
|
|
|
|
if (result)
|
|
{
|
|
return;
|
|
}
|
|
|
|
result = fallback;
|
|
}
|
|
|
|
inline int32_t __stdcall fallback_RoGetAgileReference(uint32_t, winrt::guid const& iid, void* object, void** reference) noexcept
|
|
{
|
|
*reference = nullptr;
|
|
static constexpr guid git_clsid{ 0x00000323, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
|
|
|
|
com_ptr<IGlobalInterfaceTable> git;
|
|
hresult hr = WINRT_IMPL_CoCreateInstance(git_clsid, nullptr, 1 /*CLSCTX_INPROC_SERVER*/, guid_of<IGlobalInterfaceTable>(), git.put_void());
|
|
|
|
if (hr < 0)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
uint32_t cookie{};
|
|
hr = git->RegisterInterfaceInGlobal(object, iid, &cookie);
|
|
|
|
if (hr < 0)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
*reference = new agile_ref_fallback(std::move(git), cookie);
|
|
return 0;
|
|
}
|
|
|
|
inline hresult get_agile_reference(winrt::guid const& iid, void* object, void** reference) noexcept
|
|
{
|
|
static int32_t(__stdcall * handler)(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept;
|
|
load_runtime_function(L"combase.dll", "RoGetAgileReference", handler, fallback_RoGetAgileReference);
|
|
return handler(0, iid, object, reference);
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename T>
|
|
struct agile_ref
|
|
{
|
|
agile_ref(std::nullptr_t = nullptr) noexcept {}
|
|
|
|
agile_ref(impl::com_ref<T> const& object)
|
|
{
|
|
if (object)
|
|
{
|
|
check_hresult(impl::get_agile_reference(guid_of<T>(), winrt::get_abi(object), m_ref.put_void()));
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] impl::com_ref<T> get() const noexcept
|
|
{
|
|
if (!m_ref)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void* result{};
|
|
m_ref->Resolve(guid_of<T>(), &result);
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return static_cast<bool>(m_ref);
|
|
}
|
|
|
|
private:
|
|
|
|
com_ptr<impl::IAgileReference> m_ref;
|
|
};
|
|
|
|
template<typename T> agile_ref(T const&)->agile_ref<impl::wrapped_type_t<T>>;
|
|
|
|
template <typename T>
|
|
agile_ref<impl::wrapped_type_t<T>> make_agile(T const& object)
|
|
{
|
|
return object;
|
|
}
|
|
}
|
|
|
|
#if defined(_MSC_VER)
|
|
#include <intrin.h>
|
|
#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<bstr_traits>;
|
|
|
|
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<impl::heap_traits> 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<wchar_t*>(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));
|
|
}
|
|
|
|
struct error_info_fallback final : IErrorInfo, IRestrictedErrorInfo, update_module_lock
|
|
{
|
|
error_info_fallback(int32_t code, void* message) noexcept :
|
|
m_code(code),
|
|
m_message(message ? *reinterpret_cast<winrt::hstring*>(&message) : message_from_hresult(code))
|
|
{
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IRestrictedErrorInfo>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = static_cast<IRestrictedErrorInfo*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IErrorInfo>(id))
|
|
{
|
|
*object = static_cast<IErrorInfo*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
*object = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
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 GetGUID(guid* value) noexcept final
|
|
{
|
|
*value = {};
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall GetSource(bstr* value) noexcept final
|
|
{
|
|
*value = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall GetDescription(bstr* value) noexcept final
|
|
{
|
|
*value = WINRT_IMPL_SysAllocString(m_message.c_str());
|
|
return *value ? error_ok : error_bad_alloc;
|
|
}
|
|
|
|
int32_t __stdcall GetHelpFile(bstr* value) noexcept final
|
|
{
|
|
*value = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall GetHelpContext(uint32_t* value) noexcept final
|
|
{
|
|
*value = 0;
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall GetErrorDetails(bstr* fallback, int32_t* error, bstr* message, bstr* capability) noexcept final
|
|
{
|
|
*fallback = nullptr;
|
|
*error = m_code;
|
|
*capability = nullptr;
|
|
*message = WINRT_IMPL_SysAllocString(m_message.c_str());
|
|
return *message ? error_ok : error_bad_alloc;
|
|
}
|
|
|
|
int32_t __stdcall GetReference(bstr* value) noexcept final
|
|
{
|
|
*value = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
|
|
hresult const m_code;
|
|
hstring const m_message;
|
|
atomic_ref_count m_references{ 1 };
|
|
};
|
|
|
|
[[noreturn]] inline void __stdcall fallback_RoFailFastWithErrorContext(int32_t) noexcept
|
|
{
|
|
abort();
|
|
}
|
|
}
|
|
|
|
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) noexcept : m_code(verify_error(code))
|
|
{
|
|
originate(code, nullptr);
|
|
}
|
|
|
|
hresult_error(hresult const code, param::hstring const& message) noexcept : m_code(verify_error(code))
|
|
{
|
|
originate(code, get_abi(message));
|
|
}
|
|
|
|
hresult_error(hresult const code, take_ownership_from_abi_t) noexcept : m_code(verify_error(code))
|
|
{
|
|
com_ptr<impl::IErrorInfo> info;
|
|
WINRT_IMPL_GetErrorInfo(0, info.put_void());
|
|
|
|
if ((m_info = info.try_as<impl::IRestrictedErrorInfo>()))
|
|
{
|
|
WINRT_VERIFY_(0, m_info->GetReference(m_debug_reference.put()));
|
|
|
|
if (auto info2 = m_info.try_as<impl::ILanguageExceptionErrorInfo2>())
|
|
{
|
|
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));
|
|
}
|
|
}
|
|
|
|
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 <typename To>
|
|
auto try_as() const noexcept
|
|
{
|
|
return m_info.try_as<To>();
|
|
}
|
|
|
|
hresult to_abi() const noexcept
|
|
{
|
|
if (m_info)
|
|
{
|
|
WINRT_IMPL_SetErrorInfo(0, m_info.try_as<impl::IErrorInfo>().get());
|
|
}
|
|
|
|
return m_code;
|
|
}
|
|
|
|
private:
|
|
|
|
static int32_t __stdcall fallback_RoOriginateLanguageException(int32_t error, void* message, void*) noexcept
|
|
{
|
|
com_ptr<impl::IErrorInfo> info(new (std::nothrow) impl::error_info_fallback(error, message), take_ownership_from_abi);
|
|
WINRT_VERIFY_(0, WINRT_IMPL_SetErrorInfo(0, info.get()));
|
|
return 1;
|
|
}
|
|
|
|
void originate(hresult const code, void* message) noexcept
|
|
{
|
|
static int32_t(__stdcall* handler)(int32_t error, void* message, void* exception) noexcept;
|
|
impl::load_runtime_function(L"combase.dll", "RoOriginateLanguageException", handler, fallback_RoOriginateLanguageException);
|
|
WINRT_VERIFY(handler(code, message, nullptr));
|
|
|
|
com_ptr<impl::IErrorInfo> info;
|
|
WINRT_VERIFY_(0, WINRT_IMPL_GetErrorInfo(0, info.put_void()));
|
|
WINRT_VERIFY(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<impl::IRestrictedErrorInfo> m_info;
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
};
|
|
|
|
struct hresult_access_denied : hresult_error
|
|
{
|
|
hresult_access_denied() noexcept : hresult_error(impl::error_access_denied) {}
|
|
hresult_access_denied(param::hstring const& message) noexcept : hresult_error(impl::error_access_denied, message) {}
|
|
hresult_access_denied(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_wrong_thread : hresult_error
|
|
{
|
|
hresult_wrong_thread() noexcept : hresult_error(impl::error_wrong_thread) {}
|
|
hresult_wrong_thread(param::hstring const& message) noexcept : hresult_error(impl::error_wrong_thread, message) {}
|
|
hresult_wrong_thread(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_not_implemented : hresult_error
|
|
{
|
|
hresult_not_implemented() noexcept : hresult_error(impl::error_not_implemented) {}
|
|
hresult_not_implemented(param::hstring const& message) noexcept : hresult_error(impl::error_not_implemented, message) {}
|
|
hresult_not_implemented(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_invalid_argument : hresult_error
|
|
{
|
|
hresult_invalid_argument() noexcept : hresult_error(impl::error_invalid_argument) {}
|
|
hresult_invalid_argument(param::hstring const& message) noexcept : hresult_error(impl::error_invalid_argument, message) {}
|
|
hresult_invalid_argument(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_out_of_bounds : hresult_error
|
|
{
|
|
hresult_out_of_bounds() noexcept : hresult_error(impl::error_out_of_bounds) {}
|
|
hresult_out_of_bounds(param::hstring const& message) noexcept : hresult_error(impl::error_out_of_bounds, message) {}
|
|
hresult_out_of_bounds(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_no_interface : hresult_error
|
|
{
|
|
hresult_no_interface() noexcept : hresult_error(impl::error_no_interface) {}
|
|
hresult_no_interface(param::hstring const& message) noexcept : hresult_error(impl::error_no_interface, message) {}
|
|
hresult_no_interface(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_class_not_available : hresult_error
|
|
{
|
|
hresult_class_not_available() noexcept : hresult_error(impl::error_class_not_available) {}
|
|
hresult_class_not_available(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_available, message) {}
|
|
hresult_class_not_available(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_class_not_registered : hresult_error
|
|
{
|
|
hresult_class_not_registered() noexcept : hresult_error(impl::error_class_not_registered) {}
|
|
hresult_class_not_registered(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_registered, message) {}
|
|
hresult_class_not_registered(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_changed_state : hresult_error
|
|
{
|
|
hresult_changed_state() noexcept : hresult_error(impl::error_changed_state) {}
|
|
hresult_changed_state(param::hstring const& message) noexcept : hresult_error(impl::error_changed_state, message) {}
|
|
hresult_changed_state(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_illegal_method_call : hresult_error
|
|
{
|
|
hresult_illegal_method_call() noexcept : hresult_error(impl::error_illegal_method_call) {}
|
|
hresult_illegal_method_call(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_method_call, message) {}
|
|
hresult_illegal_method_call(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_illegal_state_change : hresult_error
|
|
{
|
|
hresult_illegal_state_change() noexcept : hresult_error(impl::error_illegal_state_change) {}
|
|
hresult_illegal_state_change(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_state_change, message) {}
|
|
hresult_illegal_state_change(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_illegal_delegate_assignment : hresult_error
|
|
{
|
|
hresult_illegal_delegate_assignment() noexcept : hresult_error(impl::error_illegal_delegate_assignment) {}
|
|
hresult_illegal_delegate_assignment(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message) {}
|
|
hresult_illegal_delegate_assignment(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi) {}
|
|
};
|
|
|
|
struct hresult_canceled : hresult_error
|
|
{
|
|
hresult_canceled() noexcept : hresult_error(impl::error_canceled) {}
|
|
hresult_canceled(param::hstring const& message) noexcept : hresult_error(impl::error_canceled, message) {}
|
|
hresult_canceled(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi) {}
|
|
};
|
|
|
|
[[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result)
|
|
{
|
|
if (winrt_throw_hresult_handler)
|
|
{
|
|
winrt_throw_hresult_handler(0, nullptr, nullptr, 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);
|
|
}
|
|
|
|
if (result == impl::error_wrong_thread)
|
|
{
|
|
throw hresult_wrong_thread(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_not_implemented)
|
|
{
|
|
throw hresult_not_implemented(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_invalid_argument)
|
|
{
|
|
throw hresult_invalid_argument(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_out_of_bounds)
|
|
{
|
|
throw hresult_out_of_bounds(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_no_interface)
|
|
{
|
|
throw hresult_no_interface(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_class_not_available)
|
|
{
|
|
throw hresult_class_not_available(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_class_not_registered)
|
|
{
|
|
throw hresult_class_not_registered(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_changed_state)
|
|
{
|
|
throw hresult_changed_state(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_illegal_method_call)
|
|
{
|
|
throw hresult_illegal_method_call(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_illegal_state_change)
|
|
{
|
|
throw hresult_illegal_state_change(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_illegal_delegate_assignment)
|
|
{
|
|
throw hresult_illegal_delegate_assignment(take_ownership_from_abi);
|
|
}
|
|
|
|
if (result == impl::error_canceled)
|
|
{
|
|
throw hresult_canceled(take_ownership_from_abi);
|
|
}
|
|
|
|
throw hresult_error(result, take_ownership_from_abi);
|
|
}
|
|
|
|
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()
|
|
{
|
|
throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError()));
|
|
}
|
|
|
|
inline hresult check_hresult(hresult const result)
|
|
{
|
|
if (result < 0)
|
|
{
|
|
throw_hresult(result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template<typename T>
|
|
void check_nt(T result)
|
|
{
|
|
if (result != 0)
|
|
{
|
|
throw_hresult(impl::hresult_from_nt(result));
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void check_win32(T result)
|
|
{
|
|
if (result != 0)
|
|
{
|
|
throw_hresult(impl::hresult_from_win32(result));
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void check_bool(T result)
|
|
{
|
|
if (!result)
|
|
{
|
|
winrt::throw_last_error();
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
T* check_pointer(T* pointer)
|
|
{
|
|
if (!pointer)
|
|
{
|
|
throw_last_error();
|
|
}
|
|
|
|
return pointer;
|
|
}
|
|
|
|
[[noreturn]] inline void terminate() noexcept
|
|
{
|
|
static void(__stdcall * handler)(int32_t) noexcept;
|
|
impl::load_runtime_function(L"combase.dll", "RoFailFastWithErrorContext", handler, impl::fallback_RoFailFastWithErrorContext);
|
|
handler(to_hresult());
|
|
abort();
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
inline hresult check_hresult_allow_bounds(hresult const result)
|
|
{
|
|
if (result != impl::error_out_of_bounds && result != impl::error_fail && result != impl::error_file_not_found)
|
|
{
|
|
check_hresult(result);
|
|
}
|
|
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<IMarshal>(id))
|
|
{
|
|
*object = static_cast<IMarshal*>(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<IMarshal> get_marshaler() noexcept
|
|
{
|
|
com_ptr<unknown_abi> unknown;
|
|
WINRT_VERIFY_(0, WINRT_IMPL_CoCreateFreeThreadedMarshaler(nullptr, unknown.put_void()));
|
|
return unknown ? unknown.try_as<IMarshal>() : nullptr;
|
|
}
|
|
|
|
com_ptr<unknown_abi> m_object;
|
|
com_ptr<IMarshal> 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
|
|
|
|
template <typename T, typename H>
|
|
struct implements_delegate : abi_t<T>, H, update_module_lock
|
|
{
|
|
implements_delegate(H&& handler) : H(std::forward<H>(handler))
|
|
{
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
|
|
{
|
|
if (is_guid_of<T>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
|
|
{
|
|
*result = static_cast<abi_t<T>*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IMarshal>(id))
|
|
{
|
|
return make_marshaler(this, result);
|
|
}
|
|
|
|
*result = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return ++m_references;
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
auto const remaining = --m_references;
|
|
|
|
if (remaining == 0)
|
|
{
|
|
delete static_cast<delegate<T, H>*>(this);
|
|
}
|
|
|
|
return remaining;
|
|
}
|
|
|
|
private:
|
|
|
|
atomic_ref_count m_references{ 1 };
|
|
};
|
|
|
|
template <typename T, typename H>
|
|
T make_delegate(H&& handler)
|
|
{
|
|
return { static_cast<void*>(static_cast<abi_t<T>*>(new delegate<T, H>(std::forward<H>(handler)))), take_ownership_from_abi };
|
|
}
|
|
|
|
template <typename T>
|
|
T make_agile_delegate(T const& delegate) noexcept
|
|
{
|
|
if constexpr (!has_category_v<T>)
|
|
{
|
|
return delegate;
|
|
}
|
|
else
|
|
{
|
|
if (delegate.template try_as<IAgileObject>())
|
|
{
|
|
return delegate;
|
|
}
|
|
|
|
com_ptr<IAgileReference> ref;
|
|
get_agile_reference(guid_of<T>(), get_abi(delegate), ref.put_void());
|
|
|
|
if (ref)
|
|
{
|
|
return [ref = std::move(ref)](auto&& ... args)
|
|
{
|
|
T delegate;
|
|
ref->Resolve(guid_of<T>(), put_abi(delegate));
|
|
return delegate(args...);
|
|
};
|
|
}
|
|
|
|
return delegate;
|
|
}
|
|
}
|
|
|
|
template <typename R, typename... Args>
|
|
struct __declspec(novtable) variadic_delegate_abi : unknown_abi
|
|
{
|
|
virtual R invoke(Args const& ...) = 0;
|
|
};
|
|
|
|
template <typename H, typename R, typename... Args>
|
|
struct variadic_delegate final : variadic_delegate_abi<R, Args...>, H, update_module_lock
|
|
{
|
|
variadic_delegate(H&& handler) : H(std::forward<H>(handler))
|
|
{
|
|
}
|
|
|
|
R invoke(Args const& ... args) final
|
|
{
|
|
if constexpr (std::is_void_v<R>)
|
|
{
|
|
(*this)(args...);
|
|
}
|
|
else
|
|
{
|
|
return (*this)(args...);
|
|
}
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
|
|
{
|
|
if (is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
|
|
{
|
|
*result = static_cast<unknown_abi*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
*result = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
private:
|
|
|
|
atomic_ref_count m_references{ 1 };
|
|
};
|
|
|
|
template <typename R, typename... Args>
|
|
struct __declspec(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 <typename L>
|
|
delegate_base(L handler) :
|
|
delegate_base(make(std::forward<L>(handler)))
|
|
{}
|
|
|
|
template <typename F> delegate_base(F* handler) :
|
|
delegate_base([=](auto&& ... args) { return handler(args...); })
|
|
{}
|
|
|
|
template <typename O, typename M> delegate_base(O* object, M method) :
|
|
delegate_base([=](auto&& ... args) { return ((*object).*(method))(args...); })
|
|
{}
|
|
|
|
template <typename O, typename M> delegate_base(com_ptr<O>&& object, M method) :
|
|
delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); })
|
|
{
|
|
}
|
|
|
|
template <typename O, typename M> delegate_base(winrt::weak_ref<O>&& object, M method) :
|
|
delegate_base([o = std::move(object), method](auto&& ... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } })
|
|
{
|
|
}
|
|
|
|
auto operator()(Args const& ... args) const
|
|
{
|
|
return (*(variadic_delegate_abi<R, Args...> * *)this)->invoke(args...);
|
|
}
|
|
|
|
private:
|
|
|
|
template <typename H>
|
|
static delegate_base<R, Args...> make(H&& handler)
|
|
{
|
|
return { static_cast<void*>(new variadic_delegate<H, R, Args...>(std::forward<H>(handler))), take_ownership_from_abi };
|
|
}
|
|
};
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename... Args>
|
|
struct __declspec(empty_bases) delegate : impl::delegate_base<void, Args...>
|
|
{
|
|
using impl::delegate_base<void, Args...>::delegate_base;
|
|
};
|
|
|
|
template <typename R, typename... Args>
|
|
struct __declspec(empty_bases) delegate<R(Args...)> : impl::delegate_base<R, Args...>
|
|
{
|
|
using impl::delegate_base<R, Args...>::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 <typename I>
|
|
struct event_revoker
|
|
{
|
|
using method_type = int32_t(__stdcall impl::abi_t<I>::*)(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 <typename U>
|
|
event_revoker(U&& object, method_type method, event_token token) :
|
|
m_object(std::forward<U>(object)),
|
|
m_method(method),
|
|
m_token(token)
|
|
{}
|
|
|
|
~event_revoker() noexcept
|
|
{
|
|
revoke();
|
|
}
|
|
|
|
void revoke() noexcept
|
|
{
|
|
if (I object = std::exchange(m_object, {}).get())
|
|
{
|
|
((*reinterpret_cast<impl::abi_t<I>**>(&object))->*(m_method))(m_token);
|
|
}
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return m_object ? true : false;
|
|
}
|
|
|
|
private:
|
|
|
|
weak_ref<I> m_object;
|
|
method_type m_method{};
|
|
event_token m_token{};
|
|
};
|
|
|
|
template <typename I>
|
|
struct factory_event_revoker
|
|
{
|
|
using method_type = int32_t(__stdcall impl::abi_t<I>::*)(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 <typename U>
|
|
factory_event_revoker(U&& object, method_type method, event_token token) noexcept :
|
|
m_object(std::forward<U>(object)),
|
|
m_method(method),
|
|
m_token(token)
|
|
{}
|
|
|
|
~factory_event_revoker() noexcept
|
|
{
|
|
revoke();
|
|
}
|
|
|
|
void revoke() noexcept
|
|
{
|
|
if (auto object = std::exchange(m_object, {}))
|
|
{
|
|
((*reinterpret_cast<impl::abi_t<I>**>(&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 <typename I, auto Method>
|
|
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<I>() && 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<impl::abi_t<I>**>(&object))->*(Method))(m_token);
|
|
}
|
|
}
|
|
|
|
winrt::weak_ref<I> m_object{};
|
|
event_token m_token{};
|
|
};
|
|
|
|
template <typename I, auto Method>
|
|
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<I>() && 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<impl::abi_t<I>**>(&object))->*(Method))(m_token);
|
|
}
|
|
}
|
|
private:
|
|
I m_object;
|
|
event_token m_token{};
|
|
};
|
|
|
|
template <typename D, typename Revoker, typename S>
|
|
Revoker make_event_revoker(S source, event_token token)
|
|
{
|
|
return { static_cast<D const&>(*source), token };
|
|
}
|
|
|
|
template <typename T>
|
|
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<void*>(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<pointer>(this + 1);
|
|
}
|
|
|
|
atomic_ref_count m_references{ 1 };
|
|
uint32_t m_size{ 0 };
|
|
};
|
|
|
|
template <typename T>
|
|
com_ptr<event_array<T>> make_event_array(uint32_t const capacity)
|
|
{
|
|
void* raw = ::operator new(sizeof(event_array<T>) + (sizeof(T)* capacity));
|
|
#pragma warning(suppress: 6386)
|
|
return { new(raw) event_array<T>(capacity), take_ownership_from_abi };
|
|
}
|
|
|
|
inline int32_t __stdcall fallback_RoTransformError(int32_t, int32_t, void*) noexcept
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
template <typename Delegate, typename... Arg>
|
|
bool invoke(Delegate const& delegate, Arg const&... args) noexcept
|
|
{
|
|
try
|
|
{
|
|
delegate(args...);
|
|
}
|
|
catch (...)
|
|
{
|
|
int32_t const code = to_hresult();
|
|
|
|
static int32_t(__stdcall * handler)(int32_t, int32_t, void*) noexcept;
|
|
impl::load_runtime_function(L"combase.dll", "RoTransformError", handler, fallback_RoTransformError);
|
|
handler(code, 0, nullptr);
|
|
|
|
if (code == static_cast<int32_t>(0x80010108) || // RPC_E_DISCONNECTED
|
|
code == static_cast<int32_t>(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
|
|
code == static_cast<int32_t>(0x89020001)) // JSCRIPT_E_CANTEXECUTE
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename Delegate>
|
|
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)
|
|
{
|
|
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<delegate_type>((!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() = impl::make_agile_delegate(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;
|
|
}
|
|
|
|
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<delegate_type>(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<typename...Arg>
|
|
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:
|
|
|
|
event_token get_token(delegate_type const& delegate) const noexcept
|
|
{
|
|
return event_token{ reinterpret_cast<int64_t>(WINRT_IMPL_EncodePointer(get_abi(delegate))) };
|
|
}
|
|
|
|
using delegate_array = com_ptr<impl::event_array<delegate_type>>;
|
|
|
|
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<library_traits>;
|
|
|
|
inline int32_t __stdcall fallback_RoGetActivationFactory(void*, guid const&, void** factory) noexcept
|
|
{
|
|
*factory = nullptr;
|
|
return error_class_not_available;
|
|
}
|
|
|
|
|
|
template <bool isSameInterfaceAsIActivationFactory>
|
|
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);
|
|
}
|
|
|
|
static int32_t(__stdcall * handler)(void* classId, winrt::guid const& iid, void** factory) noexcept;
|
|
impl::load_runtime_function(L"combase.dll", "RoGetActivationFactory", handler, fallback_RoGetActivationFactory);
|
|
hresult hr = handler(*(void**)(&name), guid, result);
|
|
|
|
if (hr == impl::error_not_initialized)
|
|
{
|
|
auto usage = reinterpret_cast<int32_t(__stdcall*)(void** cookie) noexcept>(WINRT_IMPL_GetProcAddress(WINRT_IMPL_LoadLibraryW(L"combase.dll"), "CoIncrementMTAUsage"));
|
|
|
|
if (!usage)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
void* cookie;
|
|
usage(&cookie);
|
|
hr = handler(*(void**)(&name), guid, result);
|
|
}
|
|
|
|
if (hr == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
com_ptr<IErrorInfo> error_info;
|
|
WINRT_IMPL_GetErrorInfo(0, error_info.put_void());
|
|
|
|
std::wstring path{ static_cast<hstring const&>(name) };
|
|
std::size_t count{};
|
|
|
|
while (std::wstring::npos != (count = path.rfind('.')))
|
|
{
|
|
path.resize(count);
|
|
path += L".dll";
|
|
library_handle library(WINRT_IMPL_LoadLibraryW(path.c_str()));
|
|
path.resize(path.size() - 4);
|
|
|
|
if (!library)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto library_call = reinterpret_cast<int32_t(__stdcall*)(void* classId, void** factory)>(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory"));
|
|
|
|
if (!library_call)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
com_ptr<abi_t<Windows::Foundation::IActivationFactory>> 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 <typename Interface>
|
|
hresult get_runtime_activation_factory(param::hstring const& name, void** result) noexcept
|
|
{
|
|
return get_runtime_activation_factory_impl<std::is_same_v<Interface, Windows::Foundation::IActivationFactory>>(name, guid_of<Interface>(), result);
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename Interface = Windows::Foundation::IActivationFactory>
|
|
impl::com_ref<Interface> get_activation_factory(param::hstring const& name)
|
|
{
|
|
void* result{};
|
|
check_hresult(impl::get_runtime_activation_factory<Interface>(name, &result));
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
}
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
#endif
|
|
|
|
#if defined _M_ARM
|
|
#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM_BARRIER_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_ARM || defined _M_ARM64
|
|
int32_t const result = __iso_volatile_load32(reinterpret_cast<int32_t const volatile*>(target));
|
|
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
|
|
int64_t const result = __iso_volatile_load64(target);
|
|
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 <typename T>
|
|
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 };
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4324) // structure was padded due to alignment specifier
|
|
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;
|
|
};
|
|
#pragma warning(pop)
|
|
#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 (1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)¤t_value))
|
|
{
|
|
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<factory_cache_entry_base>);
|
|
|
|
#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM && !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<slist_entry*>(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<factory_cache_entry_base*>(reinterpret_cast<uint8_t*>(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 <typename Class, typename Interface>
|
|
struct factory_cache_entry : factory_cache_entry_base
|
|
{
|
|
template <typename F>
|
|
WINRT_IMPL_NOINLINE auto call(F&& callback)
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().add_factory<Class>();
|
|
#endif
|
|
|
|
auto object = get_activation_factory<Interface>(name_of<Class>());
|
|
|
|
if (!object.template try_as<IAgileObject>())
|
|
{
|
|
#ifdef WINRT_DIAGNOSTICS
|
|
get_diagnostics_info().non_agile_factory<Class>();
|
|
#endif
|
|
|
|
return callback(object);
|
|
}
|
|
|
|
{
|
|
factory_count_guard const guard(m_value.count);
|
|
|
|
if (nullptr == _InterlockedCompareExchangePointer(reinterpret_cast<void**>(&m_value.object), *reinterpret_cast<void**>(&object), nullptr))
|
|
{
|
|
*reinterpret_cast<void**>(&object) = nullptr;
|
|
#ifndef WINRT_NO_MODULE_LOCK
|
|
get_factory_cache().add(this);
|
|
#endif
|
|
}
|
|
|
|
return callback(*reinterpret_cast<com_ref<Interface> const*>(&m_value.object));
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename Class, typename Interface>
|
|
factory_cache_entry<Class, Interface> factory_cache_entry_v{};
|
|
|
|
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory, typename F>
|
|
auto call_factory(F&& callback)
|
|
{
|
|
auto& factory = factory_cache_entry_v<Class, Interface>;
|
|
|
|
{
|
|
factory_count_guard const guard(factory.m_value.count);
|
|
|
|
if (factory.m_value.object)
|
|
{
|
|
return callback(*reinterpret_cast<com_ref<Interface> const*>(&factory.m_value.object));
|
|
}
|
|
}
|
|
|
|
return factory.call(callback);
|
|
}
|
|
|
|
template <typename CastType, typename Class, typename Interface = Windows::Foundation::IActivationFactory, typename F>
|
|
auto call_factory_cast(F&& callback)
|
|
{
|
|
auto& factory = factory_cache_entry_v<Class, Interface>;
|
|
|
|
{
|
|
factory_count_guard const guard(factory.m_value.count);
|
|
|
|
if (factory.m_value.object)
|
|
{
|
|
return callback(*reinterpret_cast<com_ref<Interface> const*>(&factory.m_value.object));
|
|
}
|
|
}
|
|
|
|
return factory.call(static_cast<CastType>(callback));
|
|
}
|
|
|
|
template <typename Interface = Windows::Foundation::IActivationFactory>
|
|
com_ref<Interface> try_get_activation_factory(param::hstring const& name, hresult_error* exception = nullptr) noexcept
|
|
{
|
|
void* result{};
|
|
hresult const hr = get_runtime_activation_factory<Interface>(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 <typename D> struct produce<D, Windows::Foundation::IActivationFactory> : produce_base<D, Windows::Foundation::IActivationFactory>
|
|
{
|
|
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<uint32_t>(type));
|
|
|
|
if (result < 0)
|
|
{
|
|
throw_hresult(result);
|
|
}
|
|
}
|
|
|
|
inline void uninit_apartment() noexcept
|
|
{
|
|
WINRT_IMPL_CoUninitialize();
|
|
}
|
|
|
|
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
|
|
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<Class, Interface>([](auto&& factory)
|
|
{
|
|
return factory;
|
|
});
|
|
}
|
|
|
|
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
|
|
auto try_get_activation_factory() noexcept
|
|
{
|
|
return impl::try_get_activation_factory<Interface>(name_of<Class>());
|
|
}
|
|
|
|
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
|
|
auto try_get_activation_factory(hresult_error& exception) noexcept
|
|
{
|
|
return impl::try_get_activation_factory<Interface>(name_of<Class>(), &exception);
|
|
}
|
|
|
|
template <typename Interface = Windows::Foundation::IActivationFactory>
|
|
auto try_get_activation_factory(param::hstring const& name) noexcept
|
|
{
|
|
return impl::try_get_activation_factory<Interface>(name);
|
|
}
|
|
|
|
template <typename Interface = Windows::Foundation::IActivationFactory>
|
|
auto try_get_activation_factory(param::hstring const& name, hresult_error& exception) noexcept
|
|
{
|
|
return impl::try_get_activation_factory<Interface>(name, &exception);
|
|
}
|
|
|
|
inline void clear_factory_cache() noexcept
|
|
{
|
|
impl::get_factory_cache().clear();
|
|
}
|
|
|
|
template <typename Interface>
|
|
auto try_create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr)
|
|
{
|
|
return try_capture<Interface>(WINRT_IMPL_CoCreateInstance, clsid, outer, context);
|
|
}
|
|
|
|
template <typename Interface>
|
|
auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr)
|
|
{
|
|
return capture<Interface>(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 <typename T>
|
|
T ActivateInstance() const
|
|
{
|
|
IInspectable instance;
|
|
check_hresult((*(impl::abi_t<IActivationFactory>**)this)->ActivateInstance(put_abi(instance)));
|
|
return instance.try_as<T>();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T>
|
|
T fast_activate(Windows::Foundation::IActivationFactory const& factory)
|
|
{
|
|
void* result{};
|
|
check_hresult((*(impl::abi_t<Windows::Foundation::IActivationFactory>**)&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 <typename Interface>
|
|
struct cloaked : Interface {};
|
|
|
|
template <typename D, typename... I>
|
|
struct implements;
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template<typename...T>
|
|
using tuple_cat_t = decltype(std::tuple_cat(std::declval<T>()...));
|
|
|
|
template <template <typename> typename Condition, typename>
|
|
struct tuple_if_base;
|
|
|
|
template <template <typename> typename Condition, typename...T>
|
|
struct tuple_if_base<Condition, std::tuple<T...>> { using type = tuple_cat_t<typename std::conditional<Condition<T>::value, std::tuple<T>, std::tuple<>>::type...>; };
|
|
|
|
template <template <typename> typename Condition, typename T>
|
|
using tuple_if = typename tuple_if_base<Condition, T>::type;
|
|
|
|
template <typename T>
|
|
struct is_interface : std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, T>, is_classic_com_interface<T>> {};
|
|
|
|
template <typename T>
|
|
struct is_marker : std::disjunction<std::is_base_of<marker, T>, std::is_void<T>> {};
|
|
|
|
template <typename T>
|
|
struct uncloak_base
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct uncloak_base<cloaked<T>>
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using uncloak = typename uncloak_base<T>::type;
|
|
|
|
template <typename I>
|
|
struct is_cloaked : std::disjunction<
|
|
std::is_same<Windows::Foundation::IInspectable, I>,
|
|
std::negation<std::is_base_of<Windows::Foundation::IInspectable, I>>
|
|
> {};
|
|
|
|
template <typename I>
|
|
struct is_cloaked<cloaked<I>> : std::true_type {};
|
|
|
|
template <typename D, typename I, typename Enable = void>
|
|
struct producer;
|
|
|
|
template <typename D, typename T>
|
|
struct producers_base;
|
|
|
|
template <typename D, typename I, typename Enable = void>
|
|
struct producer_convert;
|
|
|
|
template <typename T>
|
|
struct producer_ref : T
|
|
{
|
|
producer_ref(producer_ref const&) = delete;
|
|
producer_ref& operator=(producer_ref const&) = delete;
|
|
producer_ref(producer_ref&&) = delete;
|
|
producer_ref& operator=(producer_ref&&) = delete;
|
|
|
|
producer_ref(void* ptr) noexcept : T(ptr, take_ownership_from_abi)
|
|
{
|
|
}
|
|
|
|
~producer_ref() noexcept
|
|
{
|
|
detach_abi(*this);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct producer_vtable
|
|
{
|
|
void* value;
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct producer_convert : producer<D, typename default_interface<I>::type>
|
|
{
|
|
operator producer_ref<I> const() const noexcept
|
|
{
|
|
return { (produce<D, typename default_interface<I>::type>*)this };
|
|
}
|
|
|
|
operator producer_vtable<I> const() const noexcept
|
|
{
|
|
return { (void*)this };
|
|
}
|
|
};
|
|
|
|
template <typename D, typename...T>
|
|
struct producers_base<D, std::tuple<T...>> : producer_convert<D, T>... {};
|
|
|
|
template <typename D, typename...T>
|
|
using producers = producers_base<D, tuple_if<is_interface, std::tuple<uncloak<T>...>>>;
|
|
|
|
template <typename D, typename... I>
|
|
struct root_implements;
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct unwrap_implements
|
|
{
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
struct unwrap_implements<T, std::void_t<typename T::implements_type>>
|
|
{
|
|
using type = typename T::implements_type;
|
|
};
|
|
|
|
template <typename T>
|
|
using unwrap_implements_t = typename unwrap_implements<T>::type;
|
|
|
|
template <typename...>
|
|
struct nested_implements
|
|
{};
|
|
|
|
template <typename First, typename... Rest>
|
|
struct nested_implements<First, Rest...>
|
|
: std::conditional_t<is_implements_v<First>,
|
|
impl::identity<First>, nested_implements<Rest...>>
|
|
{
|
|
static_assert(!is_implements_v<First> || !std::disjunction_v<is_implements<Rest>...>,
|
|
"Duplicate nested implements found");
|
|
};
|
|
|
|
template <typename D, typename Dummy = std::void_t<>, typename... I>
|
|
struct base_implements_impl
|
|
: impl::identity<root_implements<D, I...>> {};
|
|
|
|
template <typename D, typename... I>
|
|
struct base_implements_impl<D, std::void_t<typename nested_implements<I...>::type>, I...>
|
|
: nested_implements<I...> {};
|
|
|
|
template <typename D, typename... I>
|
|
using base_implements = base_implements_impl<D, void, I...>;
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct has_composable : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has_composable<T, std::void_t<typename T::composable>> : std::true_type {};
|
|
|
|
template <typename T, typename = std::void_t<>>
|
|
struct has_class_type : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct has_class_type<T, std::void_t<typename T::class_type>> : std::true_type {};
|
|
|
|
template <typename>
|
|
struct has_static_lifetime : std::false_type {};
|
|
|
|
template <typename D, typename...I>
|
|
struct has_static_lifetime<implements<D, I...>> : std::disjunction<std::is_same<static_lifetime, I>...> {};
|
|
|
|
template <typename D>
|
|
inline constexpr bool has_static_lifetime_v = has_static_lifetime<typename D::implements_type>::value;
|
|
|
|
template <typename T>
|
|
void clear_abi(T*) noexcept
|
|
{}
|
|
|
|
template <typename T>
|
|
void clear_abi(T** value) noexcept
|
|
{
|
|
*value = nullptr;
|
|
}
|
|
|
|
template <typename T>
|
|
void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] uint32_t const capacity) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
memset(ptr, 0, sizeof(T) * capacity);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void zero_abi([[maybe_unused]] void* ptr) noexcept
|
|
{
|
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
|
{
|
|
memset(ptr, 0, sizeof(T));
|
|
}
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename D, typename I>
|
|
D* get_self(I const& from) noexcept
|
|
{
|
|
return &static_cast<impl::produce<D, default_interface<I>>*>(get_abi(from))->shim();
|
|
}
|
|
|
|
template <typename D, typename I>
|
|
[[deprecated]] D* from_abi(I const& from) noexcept
|
|
{
|
|
return get_self<D>(from);
|
|
}
|
|
|
|
template <typename I, typename D>
|
|
impl::abi_t<I>* to_abi(impl::producer<D, I> const* from) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<I>*>(const_cast<impl::producer<D, I>*>(from));
|
|
}
|
|
|
|
template <typename I, typename D>
|
|
impl::abi_t<I>* to_abi(impl::producer_convert<D, I> const* from) noexcept
|
|
{
|
|
return reinterpret_cast<impl::abi_t<I>*>((impl::producer<D, default_interface<I>>*)from);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename...> struct interface_list;
|
|
|
|
template <>
|
|
struct interface_list<>
|
|
{
|
|
template <typename Traits>
|
|
static constexpr auto find(Traits const& traits) noexcept
|
|
{
|
|
return traits.not_found();
|
|
}
|
|
};
|
|
|
|
template <typename First, typename ... Rest>
|
|
struct interface_list<First, Rest...>
|
|
{
|
|
template <typename Traits>
|
|
static constexpr auto find(Traits const& traits) noexcept
|
|
{
|
|
if (traits.template test<First>())
|
|
{
|
|
return traits.template found<First>();
|
|
}
|
|
return interface_list<Rest...>::find(traits);
|
|
}
|
|
using first_interface = First;
|
|
};
|
|
|
|
template <typename, typename> struct interface_list_append_impl;
|
|
|
|
template <typename... T, typename... U>
|
|
struct interface_list_append_impl<interface_list<T...>, interface_list<U...>>
|
|
{
|
|
using type = interface_list<T..., U...>;
|
|
};
|
|
|
|
template <template <typename> class, typename...>
|
|
struct filter_impl;
|
|
|
|
template <template <typename> class Predicate, typename... T>
|
|
using filter = typename filter_impl<Predicate, unwrap_implements_t<T>...>::type;
|
|
|
|
template <template <typename> class Predicate>
|
|
struct filter_impl<Predicate>
|
|
{
|
|
using type = interface_list<>;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename T, typename... Rest>
|
|
struct filter_impl<Predicate, T, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
std::conditional_t<
|
|
Predicate<T>::value,
|
|
interface_list<winrt::impl::uncloak<T>>,
|
|
interface_list<>
|
|
>,
|
|
typename filter_impl<Predicate, Rest...>::type
|
|
>::type;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename ... T, typename ... Rest>
|
|
struct filter_impl<Predicate, interface_list<T...>, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
filter<Predicate, T...>,
|
|
filter<Predicate, Rest...>
|
|
>::type;
|
|
};
|
|
|
|
template <template <typename> class Predicate, typename D, typename ... I, typename ... Rest>
|
|
struct filter_impl<Predicate, winrt::implements<D, I...>, Rest...>
|
|
{
|
|
using type = typename interface_list_append_impl<
|
|
filter<Predicate, I...>,
|
|
filter<Predicate, Rest...>
|
|
>::type;
|
|
};
|
|
|
|
template <typename T>
|
|
using implemented_interfaces = filter<is_interface, typename T::implements_type>;
|
|
|
|
template <typename T>
|
|
struct is_uncloaked_interface : std::conjunction<is_interface<T>, std::negation<winrt::impl::is_cloaked<T>>> {};
|
|
template <typename T>
|
|
using uncloaked_interfaces = filter<is_uncloaked_interface, typename T::implements_type>;
|
|
|
|
template <typename T>
|
|
struct uncloaked_iids;
|
|
|
|
template <typename ... T>
|
|
struct uncloaked_iids<interface_list<T...>>
|
|
{
|
|
#pragma warning(suppress: 4307)
|
|
static constexpr std::array<guid, sizeof...(T)> value{ winrt::guid_of<T>() ... };
|
|
};
|
|
|
|
template <typename T, typename = void>
|
|
struct implements_default_interface
|
|
{
|
|
using type = typename default_interface<typename implemented_interfaces<T>::first_interface>::type;
|
|
};
|
|
|
|
template <typename T>
|
|
struct implements_default_interface<T, std::void_t<typename T::class_type>>
|
|
{
|
|
using type = winrt::default_interface<typename T::class_type>;
|
|
};
|
|
|
|
template <typename T>
|
|
struct default_interface<T, std::void_t<typename T::implements_type>>
|
|
{
|
|
using type = typename implements_default_interface<T>::type;
|
|
};
|
|
|
|
template<typename T>
|
|
struct find_iid_traits
|
|
{
|
|
T const* m_object;
|
|
guid const& m_guid;
|
|
|
|
template <typename I>
|
|
constexpr bool test() const noexcept
|
|
{
|
|
return is_guid_of<typename default_interface<I>::type>(m_guid);
|
|
}
|
|
|
|
template <typename I>
|
|
constexpr void* found() const noexcept
|
|
{
|
|
return to_abi<I>(m_object);
|
|
}
|
|
|
|
static constexpr void* not_found() noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
auto find_iid(T const* obj, guid const& iid) noexcept
|
|
{
|
|
return static_cast<unknown_abi*>(implemented_interfaces<T>::find(find_iid_traits<T>{ obj, iid }));
|
|
}
|
|
|
|
template <typename I>
|
|
struct has_interface_traits
|
|
{
|
|
template <typename T>
|
|
constexpr bool test() const noexcept
|
|
{
|
|
return std::is_same_v<T, I>;
|
|
}
|
|
|
|
template <typename>
|
|
static constexpr bool found() noexcept
|
|
{
|
|
return true;
|
|
}
|
|
|
|
static constexpr bool not_found() noexcept
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename I>
|
|
constexpr bool has_interface() noexcept
|
|
{
|
|
return impl::implemented_interfaces<T>::find(has_interface_traits<I>{});
|
|
}
|
|
|
|
template<typename T>
|
|
struct find_inspectable_traits
|
|
{
|
|
T const* m_object;
|
|
|
|
template <typename I>
|
|
static constexpr bool test() noexcept
|
|
{
|
|
return std::is_base_of_v<inspectable_abi, abi_t<I>>;
|
|
}
|
|
|
|
template <typename I>
|
|
constexpr void* found() const noexcept
|
|
{
|
|
return to_abi<I>(m_object);
|
|
}
|
|
|
|
static constexpr void* not_found() noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inspectable_abi* find_inspectable(T const* obj) noexcept
|
|
{
|
|
using default_interface = typename implements_default_interface<T>::type;
|
|
|
|
if constexpr (std::is_base_of_v<inspectable_abi, abi_t<default_interface>>)
|
|
{
|
|
return to_abi<default_interface>(obj);
|
|
}
|
|
else
|
|
{
|
|
return static_cast<inspectable_abi*>(implemented_interfaces<T>::find(find_inspectable_traits<T>{ obj }));
|
|
}
|
|
}
|
|
|
|
template <typename I, typename = std::void_t<>>
|
|
struct runtime_class_name
|
|
{
|
|
static hstring get()
|
|
{
|
|
throw hresult_not_implemented{};
|
|
}
|
|
};
|
|
|
|
template <typename I>
|
|
struct runtime_class_name<I, std::void_t<decltype(name_v<I>)>>
|
|
{
|
|
static hstring get()
|
|
{
|
|
return hstring{ name_of<I>() };
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct runtime_class_name<Windows::Foundation::IInspectable>
|
|
{
|
|
static hstring get()
|
|
{
|
|
return {};
|
|
}
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct producer
|
|
{
|
|
private:
|
|
produce<D, I> vtable;
|
|
};
|
|
|
|
template <typename D, typename I, typename Enable>
|
|
struct produce_base : abi_t<I>
|
|
{
|
|
D& shim() noexcept
|
|
{
|
|
return*static_cast<D*>(reinterpret_cast<producer<D, I>*>(this));
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override
|
|
{
|
|
return shim().QueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept override
|
|
{
|
|
return shim().AddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept override
|
|
{
|
|
return shim().Release();
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept override
|
|
{
|
|
return shim().GetIids(reinterpret_cast<count_type*>(count), reinterpret_cast<guid_type**>(array));
|
|
}
|
|
|
|
int32_t __stdcall GetRuntimeClassName(void** name) noexcept override
|
|
{
|
|
return shim().abi_GetRuntimeClassName(name);
|
|
}
|
|
|
|
int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final
|
|
{
|
|
return shim().abi_GetTrustLevel(trustLevel);
|
|
}
|
|
};
|
|
|
|
template <typename D, typename I>
|
|
struct producer<D, I, std::enable_if_t<is_classic_com_interface<I>::value>> : I
|
|
{
|
|
#ifndef WINRT_IMPL_IUNKNOWN_DEFINED
|
|
static_assert(std::is_void_v<I> /* dependent_false */, "To implement classic COM interfaces, you must #include <unknwn.h> before including C++/WinRT headers.");
|
|
#endif
|
|
};
|
|
|
|
template <typename D, typename I>
|
|
struct producer_convert<D, I, std::enable_if_t<is_classic_com_interface<I>::value>> : producer<D, I>
|
|
{
|
|
};
|
|
|
|
struct INonDelegatingInspectable : Windows::Foundation::IUnknown
|
|
{
|
|
INonDelegatingInspectable(std::nullptr_t = nullptr) noexcept {}
|
|
};
|
|
|
|
template <> struct abi<INonDelegatingInspectable>
|
|
{
|
|
using type = inspectable_abi;
|
|
};
|
|
|
|
template <typename D>
|
|
struct produce<D, INonDelegatingInspectable> : produce_base<D, INonDelegatingInspectable>
|
|
{
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingQueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return this->shim().NonDelegatingAddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
return this->shim().NonDelegatingRelease();
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingGetIids(count, array);
|
|
}
|
|
|
|
int32_t __stdcall GetRuntimeClassName(void** name) noexcept final
|
|
{
|
|
return this->shim().NonDelegatingGetRuntimeClassName(name);
|
|
}
|
|
};
|
|
|
|
template <bool Agile, bool UseModuleLock>
|
|
struct weak_ref;
|
|
|
|
template <bool Agile, bool UseModuleLock>
|
|
struct weak_source_producer;
|
|
|
|
template <bool Agile, bool UseModuleLock>
|
|
struct weak_source final : IWeakReferenceSource, module_lock_updater<UseModuleLock>
|
|
{
|
|
weak_ref<Agile, UseModuleLock>* that() noexcept
|
|
{
|
|
return static_cast<weak_ref<Agile, UseModuleLock>*>(reinterpret_cast<weak_source_producer<Agile, UseModuleLock>*>(this));
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IWeakReferenceSource>(id))
|
|
{
|
|
*object = static_cast<IWeakReferenceSource*>(this);
|
|
that()->increment_strong();
|
|
return 0;
|
|
}
|
|
|
|
return that()->m_object->QueryInterface(id, object);
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return that()->increment_strong();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
return that()->m_object->Release();
|
|
}
|
|
|
|
int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final
|
|
{
|
|
*weakReference = that();
|
|
that()->AddRef();
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
template <bool Agile, bool UseModuleLock>
|
|
struct weak_source_producer
|
|
{
|
|
protected:
|
|
weak_source<Agile, UseModuleLock> m_source;
|
|
};
|
|
|
|
template <bool Agile, bool UseModuleLock>
|
|
struct weak_ref final : IWeakReference, weak_source_producer<Agile, UseModuleLock>
|
|
{
|
|
weak_ref(unknown_abi* object, uint32_t const strong) noexcept :
|
|
m_object(object),
|
|
m_strong(strong)
|
|
{
|
|
WINRT_ASSERT(object);
|
|
}
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
|
|
{
|
|
if (is_guid_of<IWeakReference>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
*object = static_cast<IWeakReference*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (Agile)
|
|
{
|
|
if (is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = static_cast<unknown_abi*>(this);
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IMarshal>(id))
|
|
{
|
|
return make_marshaler(this, object);
|
|
}
|
|
}
|
|
|
|
*object = nullptr;
|
|
return error_no_interface;
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept final
|
|
{
|
|
return 1 + m_weak.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept final
|
|
{
|
|
uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1;
|
|
|
|
if (target == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final
|
|
{
|
|
uint32_t target = m_strong.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (target == 0)
|
|
{
|
|
*objectReference = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
if (m_strong.compare_exchange_weak(target, target + 1, std::memory_order_acquire, std::memory_order_relaxed))
|
|
{
|
|
int32_t hr = m_object->QueryInterface(id, objectReference);
|
|
m_strong.fetch_sub(1, std::memory_order_relaxed);
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void set_strong(uint32_t const count) noexcept
|
|
{
|
|
m_strong = count;
|
|
}
|
|
|
|
uint32_t increment_strong() noexcept
|
|
{
|
|
return 1 + m_strong.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
uint32_t decrement_strong() noexcept
|
|
{
|
|
uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1;
|
|
|
|
if (target == 0)
|
|
{
|
|
Release();
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
IWeakReferenceSource* get_source() noexcept
|
|
{
|
|
increment_strong();
|
|
return &this->m_source;
|
|
}
|
|
|
|
private:
|
|
template <bool T, bool U>
|
|
friend struct weak_source;
|
|
|
|
static_assert(sizeof(weak_source_producer<Agile, UseModuleLock>) == sizeof(weak_source<Agile, UseModuleLock>));
|
|
|
|
unknown_abi* m_object{};
|
|
std::atomic<uint32_t> m_strong{ 1 };
|
|
std::atomic<uint32_t> m_weak{ 1 };
|
|
};
|
|
|
|
template <bool>
|
|
struct __declspec(empty_bases) root_implements_composing_outer
|
|
{
|
|
protected:
|
|
static constexpr bool is_composing = false;
|
|
static constexpr inspectable_abi* m_inner = nullptr;
|
|
};
|
|
|
|
template <>
|
|
struct __declspec(empty_bases) root_implements_composing_outer<true>
|
|
{
|
|
template <typename Qi>
|
|
auto try_as() const noexcept
|
|
{
|
|
return m_inner.try_as<Qi>();
|
|
}
|
|
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return m_inner.operator bool();
|
|
}
|
|
protected:
|
|
static constexpr bool is_composing = true;
|
|
Windows::Foundation::IInspectable m_inner;
|
|
};
|
|
|
|
template <typename D, bool>
|
|
struct __declspec(empty_bases) root_implements_composable_inner
|
|
{
|
|
protected:
|
|
static constexpr inspectable_abi* outer() noexcept { return nullptr; }
|
|
|
|
template <typename, typename, typename>
|
|
friend class produce_dispatch_to_overridable_base;
|
|
};
|
|
|
|
template <typename D>
|
|
struct __declspec(empty_bases) root_implements_composable_inner<D, true> : producer<D, INonDelegatingInspectable>
|
|
{
|
|
protected:
|
|
inspectable_abi* outer() noexcept { return m_outer; }
|
|
private:
|
|
inspectable_abi* m_outer = nullptr;
|
|
|
|
template <typename, typename, typename>
|
|
friend class produce_dispatch_to_overridable_base;
|
|
|
|
template <typename>
|
|
friend struct composable_factory;
|
|
};
|
|
|
|
template <typename D, typename... I>
|
|
struct __declspec(novtable) root_implements
|
|
: root_implements_composing_outer<std::disjunction_v<std::is_same<composing, I>...>>
|
|
, root_implements_composable_inner<D, std::disjunction_v<std::is_same<composable, I>...>>
|
|
, module_lock_updater<!std::disjunction_v<std::is_same<no_module_lock, I>...>>
|
|
{
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
using root_implements_type = root_implements;
|
|
|
|
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->QueryInterface(id, object);
|
|
}
|
|
|
|
int32_t result = query_interface(id, object);
|
|
|
|
if (result == error_no_interface && this->m_inner)
|
|
{
|
|
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
uint32_t __stdcall AddRef() noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->AddRef();
|
|
}
|
|
|
|
return NonDelegatingAddRef();
|
|
}
|
|
|
|
uint32_t __stdcall Release() noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->Release();
|
|
}
|
|
|
|
return NonDelegatingRelease();
|
|
}
|
|
|
|
struct abi_guard
|
|
{
|
|
abi_guard(D& derived) :
|
|
m_derived(derived)
|
|
{
|
|
m_derived.abi_enter();
|
|
}
|
|
|
|
~abi_guard()
|
|
{
|
|
m_derived.abi_exit();
|
|
}
|
|
|
|
private:
|
|
|
|
D& m_derived;
|
|
};
|
|
|
|
void abi_enter() const noexcept {}
|
|
void abi_exit() const noexcept {}
|
|
|
|
#if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Please use winrt::make<T>(args...) to avoid allocating a C++/WinRT implementation type on the stack.
|
|
virtual void use_make_function_to_create_this_object() = 0;
|
|
#endif
|
|
|
|
protected:
|
|
|
|
virtual int32_t query_interface_tearoff(guid const&, void**) const noexcept
|
|
{
|
|
return error_no_interface;
|
|
}
|
|
|
|
root_implements() noexcept
|
|
{
|
|
}
|
|
|
|
virtual ~root_implements() noexcept
|
|
{
|
|
// If a weak reference is created during destruction, this ensures that it is also destroyed.
|
|
subtract_final_reference();
|
|
}
|
|
|
|
int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetIids(count, array);
|
|
}
|
|
|
|
return NonDelegatingGetIids(count, array);
|
|
}
|
|
|
|
int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetRuntimeClassName(name);
|
|
}
|
|
|
|
return NonDelegatingGetRuntimeClassName(name);
|
|
}
|
|
|
|
int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept
|
|
{
|
|
if (this->outer())
|
|
{
|
|
return this->outer()->GetTrustLevel(trustLevel);
|
|
}
|
|
|
|
return NonDelegatingGetTrustLevel(trustLevel);
|
|
}
|
|
|
|
uint32_t __stdcall NonDelegatingAddRef() noexcept
|
|
{
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->increment_strong();
|
|
}
|
|
|
|
uintptr_t const target = count_or_pointer + 1;
|
|
|
|
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_relaxed))
|
|
{
|
|
return static_cast<uint32_t>(target);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 1 + m_references.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
}
|
|
|
|
uint32_t __stdcall NonDelegatingRelease() noexcept
|
|
{
|
|
uint32_t const target = subtract_reference();
|
|
|
|
if (target == 0)
|
|
{
|
|
if constexpr (has_final_release::value)
|
|
{
|
|
D::final_release(std::unique_ptr<D>(static_cast<D*>(this)));
|
|
}
|
|
else
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept
|
|
{
|
|
if (is_guid_of<Windows::Foundation::IInspectable>(id) || is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
auto result = to_abi<INonDelegatingInspectable>(this);
|
|
NonDelegatingAddRef();
|
|
*object = result;
|
|
return 0;
|
|
}
|
|
|
|
int32_t result = query_interface(id, object);
|
|
|
|
if (result == error_no_interface && this->m_inner)
|
|
{
|
|
result = static_cast<unknown_abi*>(get_abi(this->m_inner))->QueryInterface(id, object);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept
|
|
{
|
|
auto const& local_iids = static_cast<D*>(this)->get_local_iids();
|
|
uint32_t const& local_count = local_iids.first;
|
|
if constexpr (root_implements_type::is_composing)
|
|
{
|
|
if (local_count > 0)
|
|
{
|
|
com_array<guid> const& inner_iids = get_interfaces(root_implements_type::m_inner);
|
|
*count = local_count + inner_iids.size();
|
|
*array = static_cast<guid*>(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count)));
|
|
if (*array == nullptr)
|
|
{
|
|
return error_bad_alloc;
|
|
}
|
|
*array = std::copy(local_iids.second, local_iids.second + local_count, *array);
|
|
std::copy(inner_iids.cbegin(), inner_iids.cend(), *array);
|
|
}
|
|
else
|
|
{
|
|
return static_cast<inspectable_abi*>(get_abi(root_implements_type::m_inner))->GetIids(count, array);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (local_count > 0)
|
|
{
|
|
*count = local_count;
|
|
*array = static_cast<guid*>(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count)));
|
|
if (*array == nullptr)
|
|
{
|
|
return error_bad_alloc;
|
|
}
|
|
std::copy(local_iids.second, local_iids.second + local_count, *array);
|
|
}
|
|
else
|
|
{
|
|
*count = 0;
|
|
*array = nullptr;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try
|
|
{
|
|
*name = detach_abi(static_cast<D*>(this)->GetRuntimeClassName());
|
|
return 0;
|
|
}
|
|
catch (...) { return to_hresult(); }
|
|
|
|
int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try
|
|
{
|
|
*trustLevel = static_cast<D*>(this)->GetTrustLevel();
|
|
return 0;
|
|
}
|
|
catch (...) { return to_hresult(); }
|
|
|
|
uint32_t subtract_final_reference() noexcept
|
|
{
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
while (true)
|
|
{
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->decrement_strong();
|
|
}
|
|
|
|
uintptr_t const target = count_or_pointer - 1;
|
|
|
|
if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_release, std::memory_order_relaxed))
|
|
{
|
|
return static_cast<uint32_t>(target);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return m_references.fetch_sub(1, std::memory_order_release) - 1;
|
|
}
|
|
}
|
|
|
|
uint32_t subtract_reference() noexcept
|
|
{
|
|
uint32_t result = subtract_final_reference();
|
|
|
|
if (result == 0)
|
|
{
|
|
// Ensure destruction happens with a stable reference count that isn't a weak reference.
|
|
m_references.store(1, std::memory_order_relaxed);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
winrt::weak_ref<T> get_weak()
|
|
{
|
|
impl::IWeakReferenceSource* weak_ref = make_weak_ref();
|
|
if (!weak_ref)
|
|
{
|
|
throw std::bad_alloc{};
|
|
}
|
|
com_ptr<impl::IWeakReferenceSource> source;
|
|
attach_abi(source, weak_ref);
|
|
|
|
winrt::weak_ref<T> result;
|
|
check_hresult(source->GetWeakReference(result.put()));
|
|
return result;
|
|
}
|
|
|
|
virtual Windows::Foundation::TrustLevel GetTrustLevel() const noexcept
|
|
{
|
|
return Windows::Foundation::TrustLevel::BaseTrust;
|
|
}
|
|
|
|
private:
|
|
|
|
class has_final_release
|
|
{
|
|
template <typename U, typename = decltype(std::declval<U>().final_release(0))> static constexpr bool get_value(int) { return true; }
|
|
template <typename> static constexpr bool get_value(...) { return false; }
|
|
|
|
public:
|
|
|
|
static constexpr bool value = get_value<D>(0);
|
|
};
|
|
|
|
using is_agile = std::negation<std::disjunction<std::is_same<non_agile, I>...>>;
|
|
using is_inspectable = std::disjunction<std::is_base_of<Windows::Foundation::IInspectable, I>...>;
|
|
using is_weak_ref_source = std::negation<std::disjunction<std::is_same<no_weak_ref, I>...>>;
|
|
using use_module_lock = std::negation<std::disjunction<std::is_same<no_module_lock, I>...>>;
|
|
using weak_ref_t = impl::weak_ref<is_agile::value, use_module_lock::value>;
|
|
|
|
std::atomic<std::conditional_t<is_weak_ref_source::value, uintptr_t, uint32_t>> m_references{ 1 };
|
|
|
|
int32_t query_interface(guid const& id, void** object) noexcept
|
|
{
|
|
*object = static_cast<D*>(this)->find_interface(id);
|
|
|
|
if (*object != nullptr)
|
|
{
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (is_agile::value)
|
|
{
|
|
if (is_guid_of<IAgileObject>(id))
|
|
{
|
|
*object = get_unknown();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if (is_guid_of<IMarshal>(id))
|
|
{
|
|
return make_marshaler(get_unknown(), object);
|
|
}
|
|
}
|
|
|
|
if constexpr (is_inspectable::value)
|
|
{
|
|
if (is_guid_of<Windows::Foundation::IInspectable>(id))
|
|
{
|
|
*object = find_inspectable();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (is_guid_of<Windows::Foundation::IUnknown>(id))
|
|
{
|
|
*object = get_unknown();
|
|
AddRef();
|
|
return 0;
|
|
}
|
|
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
if (is_guid_of<impl::IWeakReferenceSource>(id))
|
|
{
|
|
*object = make_weak_ref();
|
|
return *object ? error_ok : error_bad_alloc;
|
|
}
|
|
}
|
|
|
|
return query_interface_tearoff(id, object);
|
|
}
|
|
|
|
impl::IWeakReferenceSource* make_weak_ref() noexcept
|
|
{
|
|
if constexpr (is_weak_ref_source::value)
|
|
{
|
|
uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed);
|
|
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->get_source();
|
|
}
|
|
|
|
com_ptr<weak_ref_t> weak_ref;
|
|
*weak_ref.put() = new (std::nothrow) weak_ref_t(get_unknown(), static_cast<uint32_t>(count_or_pointer));
|
|
|
|
if (!weak_ref)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
uintptr_t const encoding = encode_weak_ref(weak_ref.get());
|
|
|
|
for (;;)
|
|
{
|
|
if (m_references.compare_exchange_weak(count_or_pointer, encoding, std::memory_order_acq_rel, std::memory_order_relaxed))
|
|
{
|
|
impl::IWeakReferenceSource* result = weak_ref->get_source();
|
|
detach_abi(weak_ref);
|
|
return result;
|
|
}
|
|
|
|
if (is_weak_ref(count_or_pointer))
|
|
{
|
|
return decode_weak_ref(count_or_pointer)->get_source();
|
|
}
|
|
|
|
weak_ref->set_strong(static_cast<uint32_t>(count_or_pointer));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified.");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
static bool is_weak_ref(intptr_t const value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified.");
|
|
return value < 0;
|
|
}
|
|
|
|
static weak_ref_t* decode_weak_ref(uintptr_t const value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified.");
|
|
return reinterpret_cast<weak_ref_t*>(value << 1);
|
|
}
|
|
|
|
static uintptr_t encode_weak_ref(weak_ref_t* value) noexcept
|
|
{
|
|
static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified.");
|
|
constexpr uintptr_t pointer_flag = static_cast<uintptr_t>(1) << ((sizeof(uintptr_t) * 8) - 1);
|
|
WINRT_ASSERT((reinterpret_cast<uintptr_t>(value) & 1) == 0);
|
|
return (reinterpret_cast<uintptr_t>(value) >> 1) | pointer_flag;
|
|
}
|
|
|
|
virtual unknown_abi* get_unknown() const noexcept = 0;
|
|
virtual std::pair<uint32_t, guid const*> get_local_iids() const noexcept = 0;
|
|
virtual hstring GetRuntimeClassName() const = 0;
|
|
virtual void* find_interface(guid const&) const noexcept = 0;
|
|
virtual inspectable_abi* find_inspectable() const noexcept = 0;
|
|
|
|
template <typename, typename, typename>
|
|
friend struct impl::produce_base;
|
|
|
|
template <typename, typename>
|
|
friend struct impl::produce;
|
|
};
|
|
|
|
#if defined(WINRT_NO_MAKE_DETECTION)
|
|
template <typename T>
|
|
using heap_implements = T;
|
|
#else
|
|
template <typename T>
|
|
struct heap_implements final : T
|
|
{
|
|
using T::T;
|
|
|
|
#if defined(_DEBUG)
|
|
void use_make_function_to_create_this_object() final
|
|
{
|
|
}
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
template<typename T>
|
|
class has_initializer
|
|
{
|
|
template <typename U, typename = decltype(std::declval<U>().InitializeComponent())> static constexpr bool get_value(int) { return true; }
|
|
template <typename> static constexpr bool get_value(...) { return false; }
|
|
|
|
public:
|
|
static constexpr bool value = get_value<T>(0);
|
|
};
|
|
|
|
template<typename T, typename... Args>
|
|
T* create_and_initialize(Args&&... args)
|
|
{
|
|
com_ptr<T> instance{ new heap_implements<T>(std::forward<Args>(args)...), take_ownership_from_abi };
|
|
|
|
if constexpr (has_initializer<T>::value)
|
|
{
|
|
instance->InitializeComponent();
|
|
}
|
|
|
|
return instance.detach();
|
|
}
|
|
|
|
inline com_ptr<IStaticLifetimeCollection> get_static_lifetime_map()
|
|
{
|
|
auto const lifetime_factory = get_activation_factory<impl::IStaticLifetime>(L"Windows.ApplicationModel.Core.CoreApplication");
|
|
Windows::Foundation::IUnknown collection;
|
|
check_hresult(lifetime_factory->GetCollection(put_abi(collection)));
|
|
return collection.as<IStaticLifetimeCollection>();
|
|
}
|
|
|
|
template <typename D>
|
|
auto make_factory() -> typename impl::implements_default_interface<D>::type
|
|
{
|
|
using result_type = typename impl::implements_default_interface<D>::type;
|
|
|
|
if constexpr (!has_static_lifetime_v<D>)
|
|
{
|
|
return { to_abi<result_type>(create_and_initialize<D>()), take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
auto const map = get_static_lifetime_map();
|
|
param::hstring const name{ name_of<typename D::instance_type>() };
|
|
void* result{};
|
|
map->Lookup(get_abi(name), &result);
|
|
|
|
if (result)
|
|
{
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
|
|
result_type object{ to_abi<result_type>(create_and_initialize<D>()), take_ownership_from_abi };
|
|
|
|
static slim_mutex lock;
|
|
slim_lock_guard const guard{ lock };
|
|
map->Lookup(get_abi(name), &result);
|
|
|
|
if (result)
|
|
{
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
bool found;
|
|
check_hresult(map->Insert(get_abi(name), get_abi(object), &found));
|
|
return object;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
auto detach_from(T&& object) noexcept
|
|
{
|
|
return detach_abi(std::forward<T>(object));
|
|
}
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <typename D, typename... Args>
|
|
auto make(Args&&... args)
|
|
{
|
|
#if !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Note: https://aka.ms/cppwinrt/detect_direct_allocations
|
|
static_assert(std::is_destructible_v<D>, "C++/WinRT implementation types must have a public destructor");
|
|
static_assert(!std::is_final_v<D>, "C++/WinRT implementation types must not be final");
|
|
#endif
|
|
|
|
using I = typename impl::implements_default_interface<D>::type;
|
|
|
|
if constexpr (std::is_same_v<I, Windows::Foundation::IActivationFactory>)
|
|
{
|
|
static_assert(sizeof...(args) == 0);
|
|
return impl::make_factory<D>();
|
|
}
|
|
else if constexpr (impl::has_composable<D>::value)
|
|
{
|
|
impl::com_ref<I> result{ to_abi<I>(impl::create_and_initialize<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
return result.template as<typename D::composable>();
|
|
}
|
|
else if constexpr (impl::has_class_type<D>::value)
|
|
{
|
|
static_assert(std::is_same_v<I, default_interface<typename D::class_type>>);
|
|
return typename D::class_type{ to_abi<I>(impl::create_and_initialize<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
return impl::com_ref<I>{ to_abi<I>(impl::create_and_initialize<D>(std::forward<Args>(args)...)), take_ownership_from_abi };
|
|
}
|
|
}
|
|
|
|
template <typename D, typename... Args>
|
|
com_ptr<D> make_self(Args&&... args)
|
|
{
|
|
#if !defined(WINRT_NO_MAKE_DETECTION)
|
|
// Note: https://aka.ms/cppwinrt/detect_direct_allocations
|
|
static_assert(std::is_destructible_v<D>, "C++/WinRT implementation types must have a public destructor");
|
|
static_assert(!std::is_final_v<D>, "C++/WinRT implementation types must not be final");
|
|
#endif
|
|
if constexpr (std::is_same_v<typename impl::implements_default_interface<D>::type, Windows::Foundation::IActivationFactory>)
|
|
{
|
|
static_assert(sizeof...(args) == 0);
|
|
auto temp = impl::make_factory<D>();
|
|
void* result = get_self<D>(temp);
|
|
detach_abi(temp);
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
else
|
|
{
|
|
return { impl::create_and_initialize<D>(std::forward<Args>(args)...), take_ownership_from_abi };
|
|
}
|
|
}
|
|
|
|
template <typename... FactoryClasses>
|
|
inline void clear_factory_static_lifetime()
|
|
{
|
|
auto unregister = [map = impl::get_static_lifetime_map()](param::hstring name)
|
|
{
|
|
map->Remove(get_abi(name));
|
|
};
|
|
((unregister(name_of<typename FactoryClasses::instance_type>())), ...);
|
|
}
|
|
|
|
template <typename D, typename... I>
|
|
struct implements : impl::producers<D, I...>, impl::base_implements<D, I...>::type
|
|
{
|
|
protected:
|
|
|
|
using base_type = typename impl::base_implements<D, I...>::type;
|
|
using root_implements_type = typename base_type::root_implements_type;
|
|
|
|
using base_type::base_type;
|
|
|
|
public:
|
|
|
|
using implements_type = implements;
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
|
|
weak_ref<D> get_weak()
|
|
{
|
|
return root_implements_type::template get_weak<D>();
|
|
}
|
|
|
|
com_ptr<D> get_strong() noexcept
|
|
{
|
|
com_ptr<D> result;
|
|
result.copy_from(static_cast<D*>(this));
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
auto get_abi(T const& value) const noexcept
|
|
{
|
|
return winrt::get_abi(value);
|
|
}
|
|
|
|
template <typename T>
|
|
void* get_abi() const noexcept
|
|
{
|
|
return static_cast<impl::producer_vtable<T>>(*this).value;
|
|
}
|
|
|
|
operator IInspectable() const noexcept
|
|
{
|
|
IInspectable result;
|
|
copy_from_abi(result, find_inspectable());
|
|
return result;
|
|
}
|
|
|
|
impl::hresult_type __stdcall QueryInterface(impl::guid_type const& id, void** object) noexcept
|
|
{
|
|
return root_implements_type::QueryInterface(reinterpret_cast<guid const&>(id), object);
|
|
}
|
|
|
|
impl::count_type __stdcall AddRef() noexcept
|
|
{
|
|
return root_implements_type::AddRef();
|
|
}
|
|
|
|
impl::count_type __stdcall Release() noexcept
|
|
{
|
|
return root_implements_type::Release();
|
|
}
|
|
|
|
impl::hresult_type __stdcall GetIids(impl::count_type* count, impl::guid_type** iids) noexcept
|
|
{
|
|
return root_implements_type::GetIids(reinterpret_cast<uint32_t*>(count), reinterpret_cast<guid**>(iids));
|
|
}
|
|
|
|
impl::hresult_type __stdcall GetRuntimeClassName(impl::hstring_type* value) noexcept
|
|
{
|
|
return root_implements_type::abi_GetRuntimeClassName(reinterpret_cast<void**>(value));
|
|
}
|
|
|
|
using root_implements_type::GetTrustLevel;
|
|
|
|
impl::hresult_type __stdcall GetTrustLevel(impl::trust_level_type* value) noexcept
|
|
{
|
|
return root_implements_type::abi_GetTrustLevel(reinterpret_cast<Windows::Foundation::TrustLevel*>(value));
|
|
}
|
|
|
|
void* find_interface(guid const& id) const noexcept override
|
|
{
|
|
return impl::find_iid(static_cast<const D*>(this), id);
|
|
}
|
|
|
|
impl::inspectable_abi* find_inspectable() const noexcept override
|
|
{
|
|
return impl::find_inspectable(static_cast<const D*>(this));
|
|
}
|
|
|
|
std::pair<uint32_t, guid const*> get_local_iids() const noexcept override
|
|
{
|
|
using interfaces = impl::uncloaked_interfaces<D>;
|
|
using local_iids = impl::uncloaked_iids<interfaces>;
|
|
return { static_cast<uint32_t>(local_iids::value.size()), local_iids::value.data() };
|
|
}
|
|
|
|
private:
|
|
|
|
impl::unknown_abi* get_unknown() const noexcept override
|
|
{
|
|
return reinterpret_cast<impl::unknown_abi*>(to_abi<typename impl::implements_default_interface<D>::type>(this));
|
|
}
|
|
|
|
hstring GetRuntimeClassName() const override
|
|
{
|
|
static_assert(std::is_base_of_v<implements_type, D>, "Class must derive from implements<> or ClassT<> where the first template parameter is the derived class name, e.g. struct D : implements<D, ...>");
|
|
return impl::runtime_class_name<typename impl::implements_default_interface<D>::type>::get();
|
|
}
|
|
|
|
template <typename, typename...>
|
|
friend struct impl::root_implements;
|
|
|
|
template <typename T>
|
|
friend struct weak_ref;
|
|
};
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename D>
|
|
struct composable_factory
|
|
{
|
|
template <typename I, typename... Args>
|
|
static I CreateInstance(const Windows::Foundation::IInspectable& outer, Windows::Foundation::IInspectable& inner, Args&&... args)
|
|
{
|
|
static_assert(std::is_base_of_v<Windows::Foundation::IInspectable, I>, "Requested interface must derive from winrt::Windows::Foundation::IInspectable");
|
|
inner = CreateInstanceImpl(outer, std::forward<Args>(args)...);
|
|
return inner.as<I>();
|
|
}
|
|
|
|
private:
|
|
template <typename... Args>
|
|
static Windows::Foundation::IInspectable CreateInstanceImpl(const Windows::Foundation::IInspectable& outer, Args&&... args)
|
|
{
|
|
// Very specific dance here. The return value must have a ref on the outer, while inner must have a ref count of 1.
|
|
// Be sure not to make a delegating QueryInterface call because the controlling outer is not fully constructed yet.
|
|
com_ptr<D> instance = make_self<D>(std::forward<Args>(args)...);
|
|
instance->m_outer = static_cast<inspectable_abi*>(get_abi(outer));
|
|
Windows::Foundation::IInspectable inner;
|
|
attach_abi(inner, to_abi<INonDelegatingInspectable>(detach_abi(instance)));
|
|
return inner;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename D, typename I>
|
|
class __declspec(empty_bases) produce_dispatch_to_overridable_base
|
|
{
|
|
protected:
|
|
D& shim() noexcept
|
|
{
|
|
return static_cast<T&>(*this).instance;
|
|
}
|
|
|
|
I shim_overridable()
|
|
{
|
|
void* result{};
|
|
|
|
if (shim().outer())
|
|
{
|
|
check_hresult(shim().QueryInterface(guid_of<I>(), &result));
|
|
}
|
|
|
|
return { result, take_ownership_from_abi };
|
|
}
|
|
};
|
|
|
|
template <typename T, typename D, typename I>
|
|
struct produce_dispatch_to_overridable;
|
|
|
|
template <typename D, typename... I>
|
|
class dispatch_to_overridable
|
|
{
|
|
class wrapper : public produce_dispatch_to_overridable<wrapper, D, I>...
|
|
{
|
|
D& instance;
|
|
|
|
template <typename, typename, typename>
|
|
friend class produce_dispatch_to_overridable_base;
|
|
|
|
template <typename, typename...>
|
|
friend class dispatch_to_overridable;
|
|
|
|
explicit wrapper(D& d) : instance(d) {}
|
|
|
|
public:
|
|
wrapper(const wrapper&) = delete;
|
|
wrapper(wrapper&&) = default;
|
|
};
|
|
|
|
public:
|
|
static wrapper overridable(D& instance) noexcept
|
|
{
|
|
return wrapper{ instance };
|
|
}
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt::Windows::Foundation
|
|
{
|
|
struct Point
|
|
{
|
|
float X;
|
|
float Y;
|
|
|
|
Point() noexcept = default;
|
|
|
|
constexpr Point(float X, float Y) noexcept
|
|
: X(X), Y(Y)
|
|
{}
|
|
|
|
#ifdef WINRT_IMPL_NUMERICS
|
|
|
|
constexpr Point(Numerics::float2 const& value) noexcept
|
|
: X(value.x), Y(value.y)
|
|
{}
|
|
|
|
operator Numerics::float2() const noexcept
|
|
{
|
|
return { X, Y };
|
|
}
|
|
|
|
#endif
|
|
};
|
|
|
|
constexpr bool operator==(Point const& left, Point const& right) noexcept
|
|
{
|
|
return left.X == right.X && left.Y == right.Y;
|
|
}
|
|
|
|
constexpr bool operator!=(Point const& left, Point const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
struct Size
|
|
{
|
|
float Width;
|
|
float Height;
|
|
|
|
Size() noexcept = default;
|
|
|
|
constexpr Size(float Width, float Height) noexcept
|
|
: Width(Width), Height(Height)
|
|
{}
|
|
|
|
#ifdef WINRT_IMPL_NUMERICS
|
|
|
|
constexpr Size(Numerics::float2 const& value) noexcept
|
|
: Width(value.x), Height(value.y)
|
|
{}
|
|
|
|
operator Numerics::float2() const noexcept
|
|
{
|
|
return { Width, Height };
|
|
}
|
|
|
|
#endif
|
|
};
|
|
|
|
constexpr bool operator==(Size const& left, Size const& right) noexcept
|
|
{
|
|
return left.Width == right.Width && left.Height == right.Height;
|
|
}
|
|
|
|
constexpr bool operator!=(Size const& left, Size const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
|
|
struct Rect
|
|
{
|
|
float X;
|
|
float Y;
|
|
float Width;
|
|
float Height;
|
|
|
|
Rect() noexcept = default;
|
|
|
|
constexpr Rect(float X, float Y, float Width, float Height) noexcept :
|
|
X(X), Y(Y), Width(Width), Height(Height)
|
|
{}
|
|
|
|
constexpr Rect(Point const& point, Size const& size) noexcept :
|
|
X(point.X), Y(point.Y), Width(size.Width), Height(size.Height)
|
|
{}
|
|
};
|
|
|
|
constexpr bool operator==(Rect const& left, Rect const& right) noexcept
|
|
{
|
|
return left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height;
|
|
}
|
|
|
|
constexpr bool operator!=(Rect const& left, Rect const& right) noexcept
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Point> = L"Windows.Foundation.Point";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Size> = L"Windows.Foundation.Size";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Rect> = L"Windows.Foundation.Rect";
|
|
|
|
template <> struct category<Windows::Foundation::Point>
|
|
{
|
|
using type = struct_category<float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Size>
|
|
{
|
|
using type = struct_category<float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Rect>
|
|
{
|
|
using type = struct_category<float, float, float, float>;
|
|
};
|
|
|
|
#ifdef WINRT_IMPL_NUMERICS
|
|
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float2> = L"Windows.Foundation.Numerics.Vector2";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float3> = L"Windows.Foundation.Numerics.Vector3";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float4> = L"Windows.Foundation.Numerics.Vector4";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float3x2> = L"Windows.Foundation.Numerics.Matrix3x2";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::float4x4> = L"Windows.Foundation.Numerics.Matrix4x4";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::quaternion> = L"Windows.Foundation.Numerics.Quaternion";
|
|
template <> inline constexpr auto& name_v<Windows::Foundation::Numerics::plane> = L"Windows.Foundation.Numerics.Plane";
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::float2>
|
|
{
|
|
using type = struct_category<float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::float3>
|
|
{
|
|
using type = struct_category<float, float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::float4>
|
|
{
|
|
using type = struct_category<float, float, float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::float3x2>
|
|
{
|
|
using type = struct_category<float, float, float, float, float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::float4x4>
|
|
{
|
|
using type = struct_category<
|
|
float, float, float, float,
|
|
float, float, float, float,
|
|
float, float, float, float,
|
|
float, float, float, float
|
|
>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::quaternion>
|
|
{
|
|
using type = struct_category<float, float, float, float>;
|
|
};
|
|
|
|
template <> struct category<Windows::Foundation::Numerics::plane>
|
|
{
|
|
using type = struct_category<Windows::Foundation::Numerics::float3, float>;
|
|
};
|
|
|
|
#endif
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
struct file_time
|
|
{
|
|
uint64_t value{};
|
|
|
|
file_time() noexcept = default;
|
|
|
|
constexpr explicit file_time(uint64_t const value) noexcept : value(value)
|
|
{
|
|
}
|
|
|
|
#ifdef _FILETIME_
|
|
constexpr file_time(FILETIME const& value) noexcept
|
|
: value(value.dwLowDateTime | (static_cast<uint64_t>(value.dwHighDateTime) << 32))
|
|
{
|
|
}
|
|
|
|
operator FILETIME() const noexcept
|
|
{
|
|
return { static_cast<DWORD>(value & 0xFFFFFFFF), static_cast<DWORD>(value >> 32) };
|
|
}
|
|
#endif
|
|
};
|
|
|
|
struct clock
|
|
{
|
|
using rep = int64_t;
|
|
using period = impl::filetime_period;
|
|
using duration = Windows::Foundation::TimeSpan;
|
|
using time_point = Windows::Foundation::DateTime;
|
|
|
|
static constexpr bool is_steady = false;
|
|
|
|
static time_point now() noexcept
|
|
{
|
|
file_time ft;
|
|
WINRT_IMPL_GetSystemTimePreciseAsFileTime(&ft);
|
|
return from_file_time(ft);
|
|
}
|
|
|
|
static time_t to_time_t(time_point const& time) noexcept
|
|
{
|
|
return static_cast<time_t>(std::chrono::system_clock::to_time_t(to_sys(std::chrono::time_point_cast<std::chrono::system_clock::duration>(time))));
|
|
}
|
|
|
|
static time_point from_time_t(time_t time) noexcept
|
|
{
|
|
return from_sys(std::chrono::system_clock::from_time_t(time));
|
|
}
|
|
|
|
static file_time to_file_time(time_point const& time) noexcept
|
|
{
|
|
return file_time{ static_cast<uint64_t>(time.time_since_epoch().count()) };
|
|
}
|
|
|
|
static time_point from_file_time(file_time const& time) noexcept
|
|
{
|
|
return time_point{ duration{ time.value } };
|
|
}
|
|
|
|
static auto to_FILETIME(time_point const& time) noexcept
|
|
{
|
|
return to_file_time(time);
|
|
}
|
|
|
|
static time_point from_FILETIME(file_time const& time) noexcept
|
|
{
|
|
return from_file_time(time);
|
|
}
|
|
|
|
template <typename Duration>
|
|
static std::chrono::time_point<std::chrono::system_clock, std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_sys(std::chrono::time_point<clock, Duration> const& tp)
|
|
{
|
|
return epoch + tp.time_since_epoch();
|
|
}
|
|
|
|
template <typename Duration>
|
|
static std::chrono::time_point<clock, std::common_type_t<Duration, std::chrono::seconds>>
|
|
from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp)
|
|
{
|
|
using result_t = std::chrono::time_point<clock, std::common_type_t<Duration, std::chrono::seconds>>;
|
|
return result_t{ tp - epoch };
|
|
}
|
|
|
|
private:
|
|
|
|
// system_clock epoch is 00:00:00, Jan 1 1970.
|
|
// This is 11644473600 seconds after Windows FILETIME epoch of 00:00:00, Jan 1 1601.
|
|
static constexpr std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> epoch{ std::chrono::seconds{ -11644473600 } };
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
struct access_token : handle
|
|
{
|
|
static access_token process()
|
|
{
|
|
access_token token;
|
|
check_bool(WINRT_IMPL_OpenProcessToken(WINRT_IMPL_GetCurrentProcess(), 0x0002 /*TOKEN_DUPLICATE*/, token.put()));
|
|
access_token duplicate;
|
|
check_bool(WINRT_IMPL_DuplicateToken(token.get(), 2 /*SecurityImpersonation*/, duplicate.put()));
|
|
return duplicate;
|
|
}
|
|
|
|
static access_token thread()
|
|
{
|
|
access_token token;
|
|
|
|
if (!WINRT_IMPL_OpenThreadToken(WINRT_IMPL_GetCurrentThread(), 0x0004 /*TOKEN_IMPERSONATE*/, 1, token.put()))
|
|
{
|
|
uint32_t const error = WINRT_IMPL_GetLastError();
|
|
|
|
if (error != 1008 /*ERROR_NO_TOKEN*/)
|
|
{
|
|
throw_hresult(impl::hresult_from_win32(error));
|
|
}
|
|
}
|
|
|
|
return token;
|
|
}
|
|
|
|
static access_token client()
|
|
{
|
|
struct impersonate_guard
|
|
{
|
|
impersonate_guard(com_ptr<impl::IServerSecurity> const& server) : m_server(server)
|
|
{
|
|
check_hresult(m_server->ImpersonateClient());
|
|
}
|
|
|
|
~impersonate_guard()
|
|
{
|
|
check_hresult(m_server->RevertToSelf());
|
|
}
|
|
|
|
private:
|
|
|
|
com_ptr<impl::IServerSecurity> const& m_server;
|
|
};
|
|
|
|
auto server = capture<impl::IServerSecurity>(WINRT_IMPL_CoGetCallContext);
|
|
impersonate_guard impersonate(server);
|
|
return thread();
|
|
}
|
|
|
|
access_token() = default;
|
|
access_token(access_token&& other) = default;
|
|
access_token& operator=(access_token&& other) = default;
|
|
|
|
access_token impersonate() const
|
|
{
|
|
auto previous = thread();
|
|
check_bool(WINRT_IMPL_SetThreadToken(nullptr, get()));
|
|
return previous;
|
|
}
|
|
|
|
void revert() const
|
|
{
|
|
check_bool(WINRT_IMPL_SetThreadToken(nullptr, get()));
|
|
}
|
|
|
|
auto operator()() const
|
|
{
|
|
struct guard
|
|
{
|
|
guard(access_token&& previous) noexcept : m_previous(std::move(previous))
|
|
{
|
|
}
|
|
|
|
~guard()
|
|
{
|
|
m_previous.revert();
|
|
}
|
|
|
|
guard(guard const&)
|
|
{
|
|
// A Visual C++ compiler bug (550631) requires the copy constructor even though it is never called.
|
|
WINRT_ASSERT(false);
|
|
}
|
|
|
|
private:
|
|
|
|
access_token const m_previous;
|
|
};
|
|
|
|
return guard(impersonate());
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
inline size_t hash_data(void const* ptr, size_t const bytes) noexcept
|
|
{
|
|
#ifdef _WIN64
|
|
constexpr size_t fnv_offset_basis = 14695981039346656037ULL;
|
|
constexpr size_t fnv_prime = 1099511628211ULL;
|
|
#else
|
|
constexpr size_t fnv_offset_basis = 2166136261U;
|
|
constexpr size_t fnv_prime = 16777619U;
|
|
#endif
|
|
size_t result = fnv_offset_basis;
|
|
uint8_t const* const buffer = static_cast<uint8_t const*>(ptr);
|
|
|
|
for (size_t next = 0; next < bytes; ++next)
|
|
{
|
|
result ^= buffer[next];
|
|
result *= fnv_prime;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
struct hash_base
|
|
{
|
|
size_t operator()(Windows::Foundation::IUnknown const& value) const noexcept
|
|
{
|
|
void* const abi_value = get_abi(value.try_as<Windows::Foundation::IUnknown>());
|
|
return std::hash<void*>{}(abi_value);
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace std
|
|
{
|
|
template<> struct hash<winrt::hstring>
|
|
{
|
|
size_t operator()(winrt::hstring const& value) const noexcept
|
|
{
|
|
return std::hash<std::wstring_view>{}(value);
|
|
}
|
|
};
|
|
|
|
template<> struct hash<winrt::Windows::Foundation::IUnknown> : winrt::impl::hash_base {};
|
|
template<> struct hash<winrt::Windows::Foundation::IInspectable> : winrt::impl::hash_base {};
|
|
template<> struct hash<winrt::Windows::Foundation::IActivationFactory> : winrt::impl::hash_base {};
|
|
|
|
template<> struct hash<winrt::guid>
|
|
{
|
|
size_t operator()(winrt::guid const& value) const noexcept
|
|
{
|
|
return winrt::impl::hash_data(&value, sizeof(value));
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T>
|
|
struct fast_iterator
|
|
{
|
|
using iterator_concept = std::random_access_iterator_tag;
|
|
using iterator_category = std::input_iterator_tag;
|
|
using value_type = decltype(std::declval<T>().GetAt(0));
|
|
using difference_type = ptrdiff_t;
|
|
using pointer = void;
|
|
using reference = value_type;
|
|
|
|
fast_iterator() noexcept = default;
|
|
|
|
fast_iterator(T const& collection, uint32_t const index) noexcept :
|
|
m_collection(&collection),
|
|
m_index(index)
|
|
{}
|
|
|
|
fast_iterator& operator++() noexcept
|
|
{
|
|
++m_index;
|
|
return *this;
|
|
}
|
|
|
|
fast_iterator operator++(int) noexcept
|
|
{
|
|
auto previous = *this;
|
|
++m_index;
|
|
return previous;
|
|
}
|
|
|
|
fast_iterator& operator--() noexcept
|
|
{
|
|
--m_index;
|
|
return *this;
|
|
}
|
|
|
|
fast_iterator operator--(int) noexcept
|
|
{
|
|
auto previous = *this;
|
|
--m_index;
|
|
return previous;
|
|
}
|
|
|
|
fast_iterator& operator+=(difference_type n) noexcept
|
|
{
|
|
m_index += static_cast<uint32_t>(n);
|
|
return *this;
|
|
}
|
|
|
|
fast_iterator operator+(difference_type n) const noexcept
|
|
{
|
|
return fast_iterator(*this) += n;
|
|
}
|
|
|
|
fast_iterator& operator-=(difference_type n) noexcept
|
|
{
|
|
return *this += -n;
|
|
}
|
|
|
|
fast_iterator operator-(difference_type n) const noexcept
|
|
{
|
|
return *this + -n;
|
|
}
|
|
|
|
difference_type operator-(fast_iterator const& other) const noexcept
|
|
{
|
|
WINRT_ASSERT(m_collection == other.m_collection);
|
|
return static_cast<difference_type>(m_index) - static_cast<difference_type>(other.m_index);
|
|
}
|
|
|
|
reference operator*() const
|
|
{
|
|
return m_collection->GetAt(m_index);
|
|
}
|
|
|
|
reference operator[](difference_type n) const
|
|
{
|
|
return m_collection->GetAt(m_index + static_cast<uint32_t>(n));
|
|
}
|
|
|
|
bool operator==(fast_iterator const& other) const noexcept
|
|
{
|
|
WINRT_ASSERT(m_collection == other.m_collection);
|
|
return m_index == other.m_index;
|
|
}
|
|
|
|
bool operator<(fast_iterator const& other) const noexcept
|
|
{
|
|
WINRT_ASSERT(m_collection == other.m_collection);
|
|
return m_index < other.m_index;
|
|
}
|
|
|
|
bool operator>(fast_iterator const& other) const noexcept
|
|
{
|
|
WINRT_ASSERT(m_collection == other.m_collection);
|
|
return m_index > other.m_index;
|
|
}
|
|
|
|
bool operator!=(fast_iterator const& other) const noexcept
|
|
{
|
|
return !(*this == other);
|
|
}
|
|
|
|
bool operator<=(fast_iterator const& other) const noexcept
|
|
{
|
|
return !(*this > other);
|
|
}
|
|
|
|
bool operator>=(fast_iterator const& other) const noexcept
|
|
{
|
|
return !(*this < other);
|
|
}
|
|
|
|
friend fast_iterator operator+(difference_type n, fast_iterator it) noexcept
|
|
{
|
|
return it + n;
|
|
}
|
|
|
|
friend fast_iterator operator-(difference_type n, fast_iterator it) noexcept
|
|
{
|
|
return it - n;
|
|
}
|
|
|
|
private:
|
|
|
|
T const* m_collection = nullptr;
|
|
uint32_t m_index = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class has_GetAt
|
|
{
|
|
template <typename U, typename = decltype(std::declval<U>().GetAt(0))> static constexpr bool get_value(int) { return true; }
|
|
template <typename> static constexpr bool get_value(...) { return false; }
|
|
|
|
public:
|
|
|
|
static constexpr bool value = get_value<T>(0);
|
|
};
|
|
|
|
template <typename T, std::enable_if_t<!has_GetAt<T>::value, int> = 0>
|
|
auto get_begin_iterator(T const& collection) -> decltype(collection.First())
|
|
{
|
|
auto result = collection.First();
|
|
|
|
if (!result.HasCurrent())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<!has_GetAt<T>::value, int> = 0>
|
|
auto get_end_iterator([[maybe_unused]] T const& collection) noexcept -> decltype(collection.First())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
|
|
fast_iterator<T> get_begin_iterator(T const& collection) noexcept
|
|
{
|
|
return { collection, 0 };
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
|
|
fast_iterator<T> get_end_iterator(T const& collection)
|
|
{
|
|
return { collection, collection.Size() };
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
|
|
auto rbegin(T const& collection)
|
|
{
|
|
return std::make_reverse_iterator(get_end_iterator(collection));
|
|
}
|
|
|
|
template <typename T, std::enable_if_t<has_GetAt<T>::value, int> = 0>
|
|
auto rend(T const& collection)
|
|
{
|
|
return std::make_reverse_iterator(get_begin_iterator(collection));
|
|
}
|
|
|
|
using std::begin;
|
|
using std::end;
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
inline auto submit_threadpool_callback(void(__stdcall* callback)(void*, void* context), void* context)
|
|
{
|
|
if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, context, nullptr))
|
|
{
|
|
throw_last_error();
|
|
}
|
|
}
|
|
|
|
inline void __stdcall resume_background_callback(void*, void* context) noexcept
|
|
{
|
|
coroutine_handle<>::from_address(context)();
|
|
};
|
|
|
|
inline auto resume_background(coroutine_handle<> handle)
|
|
{
|
|
submit_threadpool_callback(resume_background_callback, handle.address());
|
|
}
|
|
|
|
inline std::pair<int32_t, int32_t> get_apartment_type() noexcept
|
|
{
|
|
int32_t aptType;
|
|
int32_t aptTypeQualifier;
|
|
if (0 == WINRT_IMPL_CoGetApartmentType(&aptType, &aptTypeQualifier))
|
|
{
|
|
return { aptType, aptTypeQualifier };
|
|
}
|
|
else
|
|
{
|
|
return { 1 /* APTTYPE_MTA */, 1 /* APTTYPEQUALIFIER_IMPLICIT_MTA */ };
|
|
}
|
|
}
|
|
|
|
inline bool is_sta_thread() noexcept
|
|
{
|
|
auto type = get_apartment_type();
|
|
switch (type.first)
|
|
{
|
|
case 0: /* APTTYPE_STA */
|
|
case 3: /* APTTYPE_MAINSTA */
|
|
return true;
|
|
case 2: /* APTTYPE_NA */
|
|
return type.second == 3 /* APTTYPEQUALIFIER_NA_ON_STA */ ||
|
|
type.second == 5 /* APTTYPEQUALIFIER_NA_ON_MAINSTA */;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct resume_apartment_context
|
|
{
|
|
resume_apartment_context() = default;
|
|
resume_apartment_context(std::nullptr_t) : m_context(nullptr), m_context_type(-1) {}
|
|
resume_apartment_context(resume_apartment_context const&) = default;
|
|
resume_apartment_context(resume_apartment_context&& other) noexcept :
|
|
m_context(std::move(other.m_context)), m_context_type(std::exchange(other.m_context_type, -1)) {}
|
|
resume_apartment_context& operator=(resume_apartment_context const&) = default;
|
|
resume_apartment_context& operator=(resume_apartment_context&& other) noexcept
|
|
{
|
|
m_context = std::move(other.m_context);
|
|
m_context_type = std::exchange(other.m_context_type, -1);
|
|
return *this;
|
|
}
|
|
bool valid() const noexcept
|
|
{
|
|
return m_context_type >= 0;
|
|
}
|
|
|
|
com_ptr<IContextCallback> m_context = try_capture<IContextCallback>(WINRT_IMPL_CoGetObjectContext);
|
|
int32_t m_context_type = get_apartment_type().first;
|
|
};
|
|
|
|
inline int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept
|
|
{
|
|
coroutine_handle<>::from_address(args->data)();
|
|
return 0;
|
|
};
|
|
|
|
inline void resume_apartment_sync(com_ptr<IContextCallback> const& context, coroutine_handle<> handle, int32_t* failure)
|
|
{
|
|
com_callback_args args{};
|
|
args.data = handle.address();
|
|
|
|
auto result = context->ContextCallback(resume_apartment_callback, &args, guid_of<ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr);
|
|
if (result < 0)
|
|
{
|
|
// Resume the coroutine on the wrong apartment, but tell it why.
|
|
*failure = result;
|
|
handle();
|
|
}
|
|
}
|
|
|
|
struct threadpool_resume
|
|
{
|
|
threadpool_resume(com_ptr<IContextCallback> const& context, coroutine_handle<> handle, int32_t* failure) :
|
|
m_context(context), m_handle(handle), m_failure(failure) { }
|
|
com_ptr<IContextCallback> m_context;
|
|
coroutine_handle<> m_handle;
|
|
int32_t* m_failure;
|
|
};
|
|
|
|
inline void __stdcall fallback_submit_threadpool_callback(void*, void* p) noexcept
|
|
{
|
|
std::unique_ptr<threadpool_resume> state{ static_cast<threadpool_resume*>(p) };
|
|
resume_apartment_sync(state->m_context, state->m_handle, state->m_failure);
|
|
}
|
|
|
|
inline void resume_apartment_on_threadpool(com_ptr<IContextCallback> const& context, coroutine_handle<> handle, int32_t* failure)
|
|
{
|
|
auto state = std::make_unique<threadpool_resume>(context, handle, failure);
|
|
submit_threadpool_callback(fallback_submit_threadpool_callback, state.get());
|
|
state.release();
|
|
}
|
|
|
|
inline auto resume_apartment(resume_apartment_context const& context, coroutine_handle<> handle, int32_t* failure)
|
|
{
|
|
WINRT_ASSERT(context.valid());
|
|
if ((context.m_context == nullptr) || (context.m_context == try_capture<IContextCallback>(WINRT_IMPL_CoGetObjectContext)))
|
|
{
|
|
handle();
|
|
}
|
|
else if (context.m_context_type == 1 /* APTTYPE_MTA */)
|
|
{
|
|
resume_background(handle);
|
|
}
|
|
else if (is_sta_thread())
|
|
{
|
|
resume_apartment_on_threadpool(context.m_context, handle, failure);
|
|
}
|
|
else
|
|
{
|
|
resume_apartment_sync(context.m_context, handle, failure);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
class awaiter_finder
|
|
{
|
|
template <typename> static constexpr bool find_awaitable_member(...) { return false; }
|
|
template <typename> static constexpr bool find_co_await_member(...) { return false; }
|
|
template <typename> static constexpr bool find_co_await_free(...) { return false; }
|
|
|
|
#ifdef WINRT_IMPL_COROUTINES
|
|
template <typename U, typename = decltype(std::declval<U>().await_ready())> static constexpr bool find_awaitable_member(int) { return true; }
|
|
template <typename U, typename = decltype(std::declval<U>().operator co_await())> static constexpr bool find_co_await_member(int) { return true; }
|
|
template <typename U, typename = decltype(operator co_await(std::declval<U>()))> static constexpr bool find_co_await_free(int) { return true; }
|
|
#endif
|
|
|
|
public:
|
|
|
|
static constexpr bool has_awaitable_member = find_awaitable_member<T>(0);
|
|
static constexpr bool has_co_await_member = find_co_await_member<T&&>(0);
|
|
static constexpr bool has_co_await_free = find_co_await_free<T&&>(0);
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
struct cancellable_promise
|
|
{
|
|
using canceller_t = void(*)(void*);
|
|
|
|
void set_canceller(canceller_t canceller, void* context)
|
|
{
|
|
m_context = context;
|
|
m_canceller.store(canceller, std::memory_order_release);
|
|
}
|
|
|
|
void revoke_canceller()
|
|
{
|
|
while (m_canceller.exchange(nullptr, std::memory_order_acquire) == cancelling_ptr)
|
|
{
|
|
std::this_thread::yield();
|
|
}
|
|
}
|
|
|
|
void cancel()
|
|
{
|
|
auto canceller = m_canceller.exchange(cancelling_ptr, std::memory_order_acquire);
|
|
struct unique_cancellation_lock
|
|
{
|
|
cancellable_promise* promise;
|
|
~unique_cancellation_lock()
|
|
{
|
|
promise->m_canceller.store(nullptr, std::memory_order_release);
|
|
}
|
|
} lock{ this };
|
|
|
|
if ((canceller != nullptr) && (canceller != cancelling_ptr))
|
|
{
|
|
canceller(m_context);
|
|
}
|
|
}
|
|
|
|
private:
|
|
static inline auto const cancelling_ptr = reinterpret_cast<canceller_t>(1);
|
|
|
|
std::atomic<canceller_t> m_canceller{ nullptr };
|
|
void* m_context{ nullptr };
|
|
};
|
|
|
|
struct enable_await_cancellation
|
|
{
|
|
enable_await_cancellation() noexcept = default;
|
|
enable_await_cancellation(enable_await_cancellation const&) = default;
|
|
|
|
~enable_await_cancellation()
|
|
{
|
|
if (m_promise)
|
|
{
|
|
m_promise->revoke_canceller();
|
|
}
|
|
}
|
|
|
|
void operator=(enable_await_cancellation const&) = delete;
|
|
|
|
void set_cancellable_promise(cancellable_promise* promise) noexcept
|
|
{
|
|
m_promise = promise;
|
|
}
|
|
|
|
private:
|
|
|
|
cancellable_promise* m_promise = nullptr;
|
|
};
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
template <typename T>
|
|
decltype(auto) get_awaiter(T&& value) noexcept
|
|
{
|
|
#ifdef WINRT_IMPL_COROUTINES
|
|
if constexpr (awaiter_finder<T>::has_co_await_member)
|
|
{
|
|
static_assert(!awaiter_finder<T>::has_co_await_free, "Ambiguous operator co_await (as both member and free function).");
|
|
return static_cast<T&&>(value).operator co_await();
|
|
}
|
|
else if constexpr (awaiter_finder<T>::has_co_await_free)
|
|
{
|
|
return operator co_await(static_cast<T&&>(value));
|
|
}
|
|
else
|
|
{
|
|
static_assert(awaiter_finder<T>::has_awaitable_member, "Not an awaitable type");
|
|
return static_cast<T&&>(value);
|
|
}
|
|
#else
|
|
return static_cast<T&&>(value);
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
struct notify_awaiter
|
|
{
|
|
decltype(get_awaiter(std::declval<T&&>())) awaitable;
|
|
|
|
notify_awaiter(T&& awaitable_arg, [[maybe_unused]] cancellable_promise* promise = nullptr) : awaitable(get_awaiter(static_cast<T&&>(awaitable_arg)))
|
|
{
|
|
if constexpr (std::is_convertible_v<std::remove_reference_t<decltype(awaitable)>&, enable_await_cancellation&>)
|
|
{
|
|
if (promise)
|
|
{
|
|
static_cast<enable_await_cancellation&>(awaitable).set_cancellable_promise(promise);
|
|
awaitable.enable_cancellation(promise);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool await_ready()
|
|
{
|
|
if (winrt_suspend_handler)
|
|
{
|
|
winrt_suspend_handler(this);
|
|
}
|
|
|
|
return awaitable.await_ready();
|
|
}
|
|
|
|
template <typename U>
|
|
auto await_suspend(coroutine_handle<U> handle)
|
|
{
|
|
return awaitable.await_suspend(handle);
|
|
}
|
|
|
|
decltype(auto) await_resume()
|
|
{
|
|
if (winrt_resume_handler)
|
|
{
|
|
winrt_resume_handler(this);
|
|
}
|
|
|
|
return awaitable.await_resume();
|
|
}
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
[[nodiscard]] inline auto resume_background() noexcept
|
|
{
|
|
struct awaitable
|
|
{
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> handle) const
|
|
{
|
|
impl::resume_background(handle);
|
|
}
|
|
};
|
|
|
|
return awaitable{};
|
|
}
|
|
|
|
template <typename T>
|
|
[[nodiscard]] auto resume_background(T const& context) noexcept
|
|
{
|
|
struct awaitable
|
|
{
|
|
awaitable(T const& context) : m_context(context)
|
|
{
|
|
}
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> resume)
|
|
{
|
|
m_resume = resume;
|
|
|
|
if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, this, nullptr))
|
|
{
|
|
throw_last_error();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
static void __stdcall callback(void*, void* context) noexcept
|
|
{
|
|
auto that = static_cast<awaitable*>(context);
|
|
auto guard = that->m_context();
|
|
that->m_resume();
|
|
}
|
|
|
|
T const& m_context;
|
|
impl::coroutine_handle<> m_resume{ nullptr };
|
|
};
|
|
|
|
return awaitable{ context };
|
|
}
|
|
|
|
struct apartment_context
|
|
{
|
|
apartment_context() = default;
|
|
apartment_context(std::nullptr_t) : context(nullptr) { }
|
|
|
|
operator bool() const noexcept { return context.valid(); }
|
|
bool operator!() const noexcept { return !context.valid(); }
|
|
|
|
impl::resume_apartment_context context;
|
|
};
|
|
}
|
|
|
|
namespace winrt::impl
|
|
{
|
|
struct apartment_awaiter
|
|
{
|
|
apartment_context context; // make a copy because resuming may destruct the original
|
|
int32_t failure = 0;
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_resume() const
|
|
{
|
|
check_hresult(failure);
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> handle)
|
|
{
|
|
impl::resume_apartment(context.context, handle, &failure);
|
|
}
|
|
};
|
|
}
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
#ifdef WINRT_IMPL_COROUTINES
|
|
inline impl::apartment_awaiter operator co_await(apartment_context const& context)
|
|
{
|
|
return{ context };
|
|
}
|
|
#endif
|
|
|
|
[[nodiscard]] inline auto resume_after(Windows::Foundation::TimeSpan duration) noexcept
|
|
{
|
|
struct awaitable : enable_await_cancellation
|
|
{
|
|
explicit awaitable(Windows::Foundation::TimeSpan duration) noexcept :
|
|
m_duration(duration)
|
|
{
|
|
}
|
|
|
|
void enable_cancellation(cancellable_promise* promise)
|
|
{
|
|
promise->set_canceller([](void* context)
|
|
{
|
|
auto that = static_cast<awaitable*>(context);
|
|
if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending)
|
|
{
|
|
that->fire_immediately();
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return m_duration.count() <= 0;
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> handle)
|
|
{
|
|
m_handle = handle;
|
|
m_timer.attach(check_pointer(WINRT_IMPL_CreateThreadpoolTimer(callback, this, nullptr)));
|
|
int64_t relative_count = -m_duration.count();
|
|
WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0);
|
|
|
|
state expected = state::idle;
|
|
if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release))
|
|
{
|
|
fire_immediately();
|
|
}
|
|
}
|
|
|
|
void await_resume()
|
|
{
|
|
if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled)
|
|
{
|
|
throw hresult_canceled();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
static int32_t __stdcall fallback_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept
|
|
{
|
|
return 0; // pretend timer has already triggered and a callback is on its way
|
|
}
|
|
|
|
void fire_immediately() noexcept
|
|
{
|
|
static int32_t(__stdcall* handler)(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept;
|
|
impl::load_runtime_function(L"kernel32.dll", "SetThreadpoolTimerEx", handler, fallback_SetThreadpoolTimerEx);
|
|
|
|
if (handler(m_timer.get(), nullptr, 0, 0))
|
|
{
|
|
int64_t now = 0;
|
|
WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &now, 0, 0);
|
|
}
|
|
}
|
|
|
|
static void __stdcall callback(void*, void* context, void*) noexcept
|
|
{
|
|
auto that = reinterpret_cast<awaitable*>(context);
|
|
that->m_handle();
|
|
}
|
|
|
|
struct timer_traits
|
|
{
|
|
using type = impl::ptp_timer;
|
|
|
|
static void close(type value) noexcept
|
|
{
|
|
WINRT_IMPL_CloseThreadpoolTimer(value);
|
|
}
|
|
|
|
static constexpr type invalid() noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
enum class state { idle, pending, canceled };
|
|
|
|
handle_type<timer_traits> m_timer;
|
|
Windows::Foundation::TimeSpan m_duration;
|
|
impl::coroutine_handle<> m_handle;
|
|
std::atomic<state> m_state{ state::idle };
|
|
};
|
|
|
|
return awaitable{ duration };
|
|
}
|
|
|
|
#ifdef WINRT_IMPL_COROUTINES
|
|
inline auto operator co_await(Windows::Foundation::TimeSpan duration)
|
|
{
|
|
return resume_after(duration);
|
|
}
|
|
#endif
|
|
|
|
[[nodiscard]] inline auto resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept
|
|
{
|
|
struct awaitable : enable_await_cancellation
|
|
{
|
|
awaitable(void* handle, Windows::Foundation::TimeSpan timeout) noexcept :
|
|
m_timeout(timeout),
|
|
m_handle(handle)
|
|
{}
|
|
|
|
void enable_cancellation(cancellable_promise* promise)
|
|
{
|
|
promise->set_canceller([](void* context)
|
|
{
|
|
auto that = static_cast<awaitable*>(context);
|
|
if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending)
|
|
{
|
|
that->fire_immediately();
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return WINRT_IMPL_WaitForSingleObject(m_handle, 0) == 0;
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> resume)
|
|
{
|
|
m_resume = resume;
|
|
m_wait.attach(check_pointer(WINRT_IMPL_CreateThreadpoolWait(callback, this, nullptr)));
|
|
int64_t relative_count = -m_timeout.count();
|
|
int64_t* file_time = relative_count != 0 ? &relative_count : nullptr;
|
|
WINRT_IMPL_SetThreadpoolWait(m_wait.get(), m_handle, file_time);
|
|
|
|
state expected = state::idle;
|
|
if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release))
|
|
{
|
|
fire_immediately();
|
|
}
|
|
}
|
|
|
|
bool await_resume()
|
|
{
|
|
if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled)
|
|
{
|
|
throw hresult_canceled();
|
|
}
|
|
return m_result == 0;
|
|
}
|
|
|
|
private:
|
|
static int32_t __stdcall fallback_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept
|
|
{
|
|
return 0; // pretend wait has already triggered and a callback is on its way
|
|
}
|
|
|
|
void fire_immediately() noexcept
|
|
{
|
|
static int32_t(__stdcall* handler)(winrt::impl::ptp_wait, void*, void*, void*) noexcept;
|
|
impl::load_runtime_function(L"kernel32.dll", "SetThreadpoolWaitEx", handler, fallback_SetThreadpoolWaitEx);
|
|
|
|
if (handler(m_wait.get(), nullptr, nullptr, nullptr))
|
|
{
|
|
int64_t now = 0;
|
|
WINRT_IMPL_SetThreadpoolWait(m_wait.get(), WINRT_IMPL_GetCurrentProcess(), &now);
|
|
}
|
|
}
|
|
|
|
static void __stdcall callback(void*, void* context, void*, uint32_t result) noexcept
|
|
{
|
|
auto that = static_cast<awaitable*>(context);
|
|
that->m_result = result;
|
|
that->m_resume();
|
|
}
|
|
|
|
struct wait_traits
|
|
{
|
|
using type = impl::ptp_wait;
|
|
|
|
static void close(type value) noexcept
|
|
{
|
|
WINRT_IMPL_CloseThreadpoolWait(value);
|
|
}
|
|
|
|
static constexpr type invalid() noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
enum class state { idle, pending, canceled };
|
|
|
|
handle_type<wait_traits> m_wait;
|
|
Windows::Foundation::TimeSpan m_timeout;
|
|
void* m_handle;
|
|
uint32_t m_result{};
|
|
impl::coroutine_handle<> m_resume{ nullptr };
|
|
std::atomic<state> m_state{ state::idle };
|
|
};
|
|
|
|
return awaitable{ handle, timeout };
|
|
}
|
|
|
|
struct thread_pool
|
|
{
|
|
thread_pool() :
|
|
m_pool(check_pointer(WINRT_IMPL_CreateThreadpool(nullptr)))
|
|
{
|
|
m_environment.Pool = m_pool.get();
|
|
}
|
|
|
|
void thread_limits(uint32_t const high, uint32_t const low)
|
|
{
|
|
WINRT_IMPL_SetThreadpoolThreadMaximum(m_pool.get(), high);
|
|
check_bool(WINRT_IMPL_SetThreadpoolThreadMinimum(m_pool.get(), low));
|
|
}
|
|
|
|
bool await_ready() const noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void await_resume() const noexcept
|
|
{
|
|
}
|
|
|
|
void await_suspend(impl::coroutine_handle<> handle)
|
|
{
|
|
if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, handle.address(), &m_environment))
|
|
{
|
|
throw_last_error();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
static void __stdcall callback(void*, void* context) noexcept
|
|
{
|
|
impl::coroutine_handle<>::from_address(context)();
|
|
}
|
|
|
|
struct pool_traits
|
|
{
|
|
using type = impl::ptp_pool;
|
|
|
|
static void close(type value) noexcept
|
|
{
|
|
WINRT_IMPL_CloseThreadpool(value);
|
|
}
|
|
|
|
static constexpr type invalid() noexcept
|
|
{
|
|
return nullptr;
|
|
}
|
|
};
|
|
|
|
struct environment // TP_CALLBACK_ENVIRON
|
|
{
|
|
uint32_t Version{ 3 };
|
|
void* Pool{};
|
|
void* CleanupGroup{};
|
|
void* CleanupGroupCancelCallback{};
|
|
void* RaceDll{};
|
|
void* ActivationContext{};
|
|
void* FinalizationCallback{};
|
|
union
|
|
{
|
|
uint32_t Flags{};
|
|
struct
|
|
{
|
|
uint32_t LongFunction : 1;
|
|
uint32_t Persistent : 1;
|
|
uint32_t Private : 30;
|
|
} s;
|
|
} u;
|
|
int32_t CallbackPriority{ 1 };
|
|
uint32_t Size{ sizeof(environment) };
|
|
};
|
|
|
|
handle_type<pool_traits> m_pool;
|
|
environment m_environment;
|
|
};
|
|
|
|
struct fire_and_forget {};
|
|
}
|
|
|
|
#ifdef __cpp_lib_coroutine
|
|
namespace std
|
|
#else
|
|
namespace std::experimental
|
|
#endif
|
|
{
|
|
template <typename... Args>
|
|
struct coroutine_traits<winrt::fire_and_forget, Args...>
|
|
{
|
|
struct promise_type
|
|
{
|
|
winrt::fire_and_forget get_return_object() const noexcept
|
|
{
|
|
return{};
|
|
}
|
|
|
|
void return_void() const noexcept
|
|
{
|
|
}
|
|
|
|
suspend_never initial_suspend() const noexcept
|
|
{
|
|
return{};
|
|
}
|
|
|
|
suspend_never final_suspend() const noexcept
|
|
{
|
|
if (winrt_suspend_handler)
|
|
{
|
|
winrt_suspend_handler(this);
|
|
}
|
|
|
|
return{};
|
|
}
|
|
|
|
void unhandled_exception() const noexcept
|
|
{
|
|
winrt::terminate();
|
|
}
|
|
|
|
template <typename Expression>
|
|
auto await_transform(Expression&& expression)
|
|
{
|
|
return winrt::impl::notify_awaiter<Expression>{ static_cast<Expression&&>(expression) };
|
|
}
|
|
};
|
|
};
|
|
}
|
|
|
|
#if defined(_DEBUG) && !defined(WINRT_NATVIS)
|
|
#define WINRT_NATVIS
|
|
#endif
|
|
|
|
#ifdef WINRT_NATVIS
|
|
|
|
namespace winrt::impl
|
|
{
|
|
struct natvis
|
|
{
|
|
static auto __stdcall abi_val(void* object, wchar_t const * iid_str, int method)
|
|
{
|
|
union variant
|
|
{
|
|
bool b;
|
|
wchar_t c;
|
|
int8_t i1;
|
|
int16_t i2;
|
|
int32_t i4;
|
|
int64_t i8;
|
|
uint8_t u1;
|
|
uint16_t u2;
|
|
uint32_t u4;
|
|
uint64_t u8;
|
|
float r4;
|
|
double r8;
|
|
guid g;
|
|
void* s;
|
|
uint8_t v[1024];
|
|
}
|
|
value;
|
|
value.s = 0;
|
|
guid iid;
|
|
if (WINRT_IMPL_IIDFromString(iid_str, &iid) == 0)
|
|
{
|
|
struct memory_basic_information
|
|
{
|
|
void* base_address;
|
|
void* allocation_base;
|
|
uint32_t allocation_protect;
|
|
#ifdef _WIN64
|
|
uint32_t __alignment1;
|
|
#endif
|
|
uintptr_t region_size;
|
|
uint32_t state;
|
|
uint32_t protect;
|
|
uint32_t type;
|
|
#ifdef _WIN64
|
|
uint32_t __alignment2;
|
|
#endif
|
|
};
|
|
memory_basic_information info;
|
|
// validate object pointer is readable
|
|
if ((WINRT_IMPL_VirtualQuery(object, &info, sizeof(info)) != 0) && ((info.protect & 0xEE) != 0))
|
|
{
|
|
inspectable_abi* pinsp;
|
|
if (((unknown_abi*)object)->QueryInterface(iid, reinterpret_cast<void**>(&pinsp)) == 0)
|
|
{
|
|
static const int IInspectable_vtbl_size = 6;
|
|
auto vtbl = *(void***)pinsp;
|
|
// validate vtbl pointer is readable
|
|
if ((WINRT_IMPL_VirtualQuery(vtbl, &info, sizeof(info)) != 0) && ((info.protect & 0xEE) != 0))
|
|
{
|
|
auto vfunc = vtbl[method + IInspectable_vtbl_size];
|
|
// validate method pointer is executable
|
|
if ((WINRT_IMPL_VirtualQuery(vfunc, &info, sizeof(info)) != 0) && ((info.protect & 0xF0) != 0))
|
|
{
|
|
typedef int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*);
|
|
(pinsp->**(PropertyAccessor*)&vfunc)(&value);
|
|
pinsp->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
static auto __stdcall get_val(winrt::Windows::Foundation::IInspectable* object, wchar_t const* iid_str, int method)
|
|
{
|
|
return abi_val(static_cast<unknown_abi*>(get_abi(*object)), iid_str, method);
|
|
}
|
|
};
|
|
}
|
|
|
|
extern "C"
|
|
__declspec(selectany)
|
|
decltype(winrt::impl::natvis::abi_val) & WINRT_abi_val = winrt::impl::natvis::abi_val;
|
|
|
|
extern "C"
|
|
__declspec(selectany)
|
|
decltype(winrt::impl::natvis::get_val) & WINRT_get_val = winrt::impl::natvis::get_val;
|
|
|
|
#ifdef _M_IX86
|
|
#pragma comment(linker, "/include:_WINRT_abi_val")
|
|
#pragma comment(linker, "/include:_WINRT_get_val")
|
|
#else
|
|
#pragma comment(linker, "/include:WINRT_abi_val")
|
|
#pragma comment(linker, "/include:WINRT_get_val")
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// WINRT_version is used by Microsoft to analyze C++/WinRT library adoption and inform future product decisions.
|
|
extern "C"
|
|
__declspec(selectany)
|
|
char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION;
|
|
|
|
#ifdef _M_IX86
|
|
#pragma comment(linker, "/include:_WINRT_version")
|
|
#else
|
|
#pragma comment(linker, "/include:WINRT_version")
|
|
#endif
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma detect_mismatch("C++/WinRT version", CPPWINRT_VERSION)
|
|
#endif
|
|
|
|
WINRT_EXPORT namespace winrt
|
|
{
|
|
template <size_t BaseSize, size_t ComponentSize>
|
|
constexpr bool check_version(char const(&base)[BaseSize], char const(&component)[ComponentSize]) noexcept
|
|
{
|
|
if constexpr (BaseSize != ComponentSize)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i != BaseSize - 1; ++i)
|
|
{
|
|
if (base[i] != component[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|