From fba8184491e0b7ae6fab7ac01b4600d230dc4569 Mon Sep 17 00:00:00 2001 From: marsunet Date: Tue, 21 Dec 2021 17:04:22 -0800 Subject: Initial commit with window demo. --- contrib/DirectX-Headers/include/wsl/stubs/OAIdl.h | 5 + contrib/DirectX-Headers/include/wsl/stubs/OCIdl.h | 5 + contrib/DirectX-Headers/include/wsl/stubs/rpc.h | 5 + contrib/DirectX-Headers/include/wsl/stubs/rpcndr.h | 6 + .../include/wsl/stubs/winapifamily.h | 6 + .../DirectX-Headers/include/wsl/stubs/wrl/client.h | 6 + .../include/wsl/stubs/wrl/implements.h | 6 + contrib/DirectX-Headers/include/wsl/winadapter.h | 340 +++++++++ contrib/DirectX-Headers/include/wsl/wrladapter.h | 801 +++++++++++++++++++++ 9 files changed, 1180 insertions(+) create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/OAIdl.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/OCIdl.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/rpc.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/rpcndr.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/winapifamily.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/wrl/client.h create mode 100644 contrib/DirectX-Headers/include/wsl/stubs/wrl/implements.h create mode 100644 contrib/DirectX-Headers/include/wsl/winadapter.h create mode 100644 contrib/DirectX-Headers/include/wsl/wrladapter.h (limited to 'contrib/DirectX-Headers/include/wsl') diff --git a/contrib/DirectX-Headers/include/wsl/stubs/OAIdl.h b/contrib/DirectX-Headers/include/wsl/stubs/OAIdl.h new file mode 100644 index 0000000..76f5b5f --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/OAIdl.h @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub header to satisfy d3d12.h include +#pragma once \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/OCIdl.h b/contrib/DirectX-Headers/include/wsl/stubs/OCIdl.h new file mode 100644 index 0000000..76f5b5f --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/OCIdl.h @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub header to satisfy d3d12.h include +#pragma once \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/rpc.h b/contrib/DirectX-Headers/include/wsl/stubs/rpc.h new file mode 100644 index 0000000..76f5b5f --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/rpc.h @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub header to satisfy d3d12.h include +#pragma once \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/rpcndr.h b/contrib/DirectX-Headers/include/wsl/stubs/rpcndr.h new file mode 100644 index 0000000..5b5f2e8 --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/rpcndr.h @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub header to satisfy d3d12.h include +#pragma once +#define __RPCNDR_H_VERSION__ \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/winapifamily.h b/contrib/DirectX-Headers/include/wsl/stubs/winapifamily.h new file mode 100644 index 0000000..064c4c2 --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/winapifamily.h @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub header to satisfy d3d12.h include. Unconditionally light up all APIs. +#pragma once +#define WINAPI_FAMILY_PARTITION(Partitions) 1 \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/wrl/client.h b/contrib/DirectX-Headers/include/wsl/stubs/wrl/client.h new file mode 100644 index 0000000..43e7d0b --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/wrl/client.h @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub to satisfy d3dx12.h include +#pragma once +#include "../wrladapter.h" \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/stubs/wrl/implements.h b/contrib/DirectX-Headers/include/wsl/stubs/wrl/implements.h new file mode 100644 index 0000000..fb2bebc --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/stubs/wrl/implements.h @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Stub to satisfy DML TF runtime includes +#pragma once +#include "wrladapter.h" \ No newline at end of file diff --git a/contrib/DirectX-Headers/include/wsl/winadapter.h b/contrib/DirectX-Headers/include/wsl/winadapter.h new file mode 100644 index 0000000..8400f4a --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/winadapter.h @@ -0,0 +1,340 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +// These #defines prevent the idl-generated headers from trying to include +// Windows.h from the SDK rather than this one. +#define RPC_NO_WINDOWS_H +#define COM_NO_WINDOWS_H + +// Allcaps type definitions +#include +#include +#include +#include + +// Note: using fixed-width here to match Windows widths +// Specifically this is different for 'long' vs 'LONG' +typedef uint8_t UINT8; +typedef int8_t INT8; +typedef uint16_t UINT16; +typedef int16_t INT16; +typedef uint32_t UINT32, UINT, ULONG, DWORD, BOOL; +typedef int32_t INT32, INT, LONG; +typedef uint64_t UINT64, ULONG_PTR; +typedef int64_t INT64, LONG_PTR; +typedef void VOID, *HANDLE, *RPC_IF_HANDLE, *LPVOID; +typedef const void *LPCVOID; +typedef size_t SIZE_T; +typedef float FLOAT; +typedef double DOUBLE; +typedef unsigned char BYTE; +typedef int HWND; + +// Note: WCHAR is not the same between Windows and Linux, to enable +// string manipulation APIs to work with resulting strings. +// APIs to D3D/DXCore will work on Linux wchars, but beware with +// interactions directly with the Windows kernel. +typedef char CHAR, *PSTR, *LPSTR, TCHAR, *PTSTR; +typedef const char *LPCSTR, *PCSTR, *LPCTSTR, *PCTSTR; +typedef wchar_t WCHAR, *PWSTR, *LPWSTR, *PWCHAR; +typedef const wchar_t *LPCWSTR, *PCWSTR; + +#undef LONG_MAX +#define LONG_MAX INT_MAX +#undef ULONG_MAX +#define ULONG_MAX UINT_MAX + +// Misc defines +#define interface struct +#define MIDL_INTERFACE(x) interface +#define __analysis_assume(x) +#define TRUE 1u +#define FALSE 0u +#define DECLARE_INTERFACE(iface) interface iface +#define PURE = 0 +#define THIS_ +#define DECLSPEC_UUID(x) +#define DECLSPEC_NOVTABLE +#define DECLSPEC_SELECTANY +#define EXTERN_C extern "C" + +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[ 8 ]; +} GUID; + +#ifdef __cplusplus +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) extern "C" const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) extern "C" const GUID name +#endif + +template GUID uuidof() = delete; +template GUID uuidof(T*) { return uuidof(); } +template GUID uuidof(T**) { return uuidof(); } +template GUID uuidof(T&) { return uuidof(); } +#define __uuidof(x) uuidof(x) +#else +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) extern const GUID name +#endif +#endif + +typedef GUID IID; +typedef GUID UUID; +typedef GUID CLSID; +#ifdef __cplusplus +#define REFGUID const GUID & +#define REFIID const IID & +#define REFCLSID const IID & + +__inline int InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2) +{ + return ( + ((uint32_t *)&rguid1)[0] == ((uint32_t *)&rguid2)[0] && + ((uint32_t *)&rguid1)[1] == ((uint32_t *)&rguid2)[1] && + ((uint32_t *)&rguid1)[2] == ((uint32_t *)&rguid2)[2] && + ((uint32_t *)&rguid1)[3] == ((uint32_t *)&rguid2)[3]); +} +#else +#define REFGUID const GUID * +#define REFIID const IID * +#define REFCLSID const IID * +#endif + +// SAL annotations +#define _In_ +#define _In_z_ +#define _In_opt_ +#define _In_opt_z_ +#define _In_reads_(x) +#define _In_reads_opt_(x) +#define _In_reads_bytes_(x) +#define _In_reads_bytes_opt_(x) +#define _In_range_(x, y) +#define _In_bytecount_(x) +#define _Out_ +#define _Out_opt_ +#define _Outptr_ +#define _Outptr_opt_result_z_ +#define _Outptr_opt_result_bytebuffer_(x) +#define _COM_Outptr_ +#define _COM_Outptr_result_maybenull_ +#define _COM_Outptr_opt_ +#define _COM_Outptr_opt_result_maybenull_ +#define _Out_writes_(x) +#define _Out_writes_z_(x) +#define _Out_writes_opt_(x) +#define _Out_writes_all_(x) +#define _Out_writes_all_opt_(x) +#define _Out_writes_to_opt_(x, y) +#define _Out_writes_bytes_(x) +#define _Out_writes_bytes_all_(x) +#define _Out_writes_bytes_all_opt_(x) +#define _Out_writes_bytes_opt_(x) +#define _Inout_ +#define _Inout_opt_ +#define _Inout_updates_(x) +#define _Inout_updates_bytes_(x) +#define _Field_size_(x) +#define _Field_size_opt_(x) +#define _Field_size_bytes_(x) +#define _Field_size_full_(x) +#define _Field_size_bytes_full_(x) +#define _Field_size_bytes_full_opt_(x) +#define _Field_size_bytes_part_(x, y) +#define _Field_range_(x, y) +#define _Field_z_ +#define _Check_return_ +#define _IRQL_requires_(x) +#define _IRQL_requires_min_(x) +#define _IRQL_requires_max_(x) +#define _At_(x, y) +#define _Always_(x) +#define _Return_type_success_(x) +#define _Translates_Win32_to_HRESULT_(x) +#define _Maybenull_ +#define _Outptr_result_maybenull_ +#define _Outptr_result_nullonfailure_ +#define _Analysis_assume_(x) +#define _Success_(x) +#define _In_count_(x) +#define _In_opt_count_(x) +#define _Use_decl_annotations_ + +// Calling conventions +#define __cdecl +#define __stdcall +#define STDMETHODCALLTYPE +#define STDAPICALLTYPE +#define STDAPI extern "C" HRESULT STDAPICALLTYPE +#define WINAPI +#define STDMETHOD(name) virtual HRESULT name +#define STDMETHOD_(type,name) virtual type name +#define IFACEMETHOD(method) /*__override*/ STDMETHOD(method) +#define IFACEMETHOD_(type, method) /*__override*/ STDMETHOD_(type, method) + +// Error codes +typedef LONG HRESULT; +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) +#define S_OK ((HRESULT)0L) +#define S_FALSE ((HRESULT)1L) +#define E_NOTIMPL ((HRESULT)0x80000001L) +#define E_OUTOFMEMORY ((HRESULT)0x80000002L) +#define E_INVALIDARG ((HRESULT)0x80000003L) +#define E_NOINTERFACE ((HRESULT)0x80000004L) +#define E_POINTER ((HRESULT)0x80000005L) +#define E_HANDLE ((HRESULT)0x80000006L) +#define E_ABORT ((HRESULT)0x80000007L) +#define E_FAIL ((HRESULT)0x80000008L) +#define E_ACCESSDENIED ((HRESULT)0x80000009L) +#define E_UNEXPECTED ((HRESULT)0x8000FFFFL) +#define DXGI_ERROR_DEVICE_HUNG ((HRESULT)0x887A0006L) +#define DXGI_ERROR_DEVICE_REMOVED ((HRESULT)0x887A0005L) +#define DXGI_ERROR_DEVICE_RESET ((HRESULT)0x887A0007L) +#define DXGI_ERROR_DRIVER_INTERNAL_ERROR ((HRESULT)0x887A0020L) +#define DXGI_ERROR_INVALID_CALL ((HRESULT)0x887A0001L) + +typedef struct _LUID +{ + ULONG LowPart; + LONG HighPart; +} LUID; + +struct RECT +{ + int left; + int top; + int right; + int bottom; +}; + +typedef union _LARGE_INTEGER { + struct { + uint32_t LowPart; + uint32_t HighPart; + } u; + int64_t QuadPart; +} LARGE_INTEGER; + +typedef union _ULARGE_INTEGER { + struct { + uint32_t LowPart; + uint32_t HighPart; + } u; + uint64_t QuadPart; +} ULARGE_INTEGER; + +struct SECURITY_ATTRIBUTES; +struct STATSTG; + +#ifdef __cplusplus +// ENUM_FLAG_OPERATORS +// Define operator overloads to enable bit operations on enum values that are +// used to define flags. Use DEFINE_ENUM_FLAG_OPERATORS(YOUR_TYPE) to enable these +// operators on YOUR_TYPE. +extern "C++" { + template + struct _ENUM_FLAG_INTEGER_FOR_SIZE; + + template <> + struct _ENUM_FLAG_INTEGER_FOR_SIZE<1> + { + typedef int8_t type; + }; + + template <> + struct _ENUM_FLAG_INTEGER_FOR_SIZE<2> + { + typedef int16_t type; + }; + + template <> + struct _ENUM_FLAG_INTEGER_FOR_SIZE<4> + { + typedef int32_t type; + }; + + template <> + struct _ENUM_FLAG_INTEGER_FOR_SIZE<8> + { + typedef int64_t type; + }; + + // used as an approximation of std::underlying_type + template + struct _ENUM_FLAG_SIZED_INTEGER + { + typedef typename _ENUM_FLAG_INTEGER_FOR_SIZE::type type; + }; + +} +#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \ +extern "C++" { \ +inline constexpr ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER::type)a) | ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER::type &)a) |= ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline constexpr ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER::type)a) & ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER::type &)a) &= ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline constexpr ENUMTYPE operator ~ (ENUMTYPE a) { return ENUMTYPE(~((_ENUM_FLAG_SIZED_INTEGER::type)a)); } \ +inline constexpr ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER::type)a) ^ ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +inline ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER::type &)a) ^= ((_ENUM_FLAG_SIZED_INTEGER::type)b)); } \ +} +#endif + +// D3DX12 uses these +#include +#define HeapAlloc(heap, flags, size) malloc(size) +#define HeapFree(heap, flags, ptr) free(ptr) + +#ifdef __cplusplus +// IUnknown + +interface DECLSPEC_UUID("00000000-0000-0000-C000-000000000046") DECLSPEC_NOVTABLE IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef() = 0; + virtual ULONG STDMETHODCALLTYPE Release() = 0; + + template HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) { + return QueryInterface(uuidof(), (void **)pp); + } +}; + +template <> constexpr GUID uuidof() +{ + return { 0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; +} + +extern "C++" +{ + template void** IID_PPV_ARGS_Helper(T** pp) + { + static_cast(*pp); + return reinterpret_cast(pp); + } +} + +#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType) +#endif + +#if defined(lint) +// Note: lint -e530 says don't complain about uninitialized variables for +// this variable. Error 527 has to do with unreachable code. +// -restore restores checking to the -save state +#define UNREFERENCED_PARAMETER(P) \ + /*lint -save -e527 -e530 */ \ + { \ + (P) = (P); \ + } \ + /*lint -restore */ +#else +#define UNREFERENCED_PARAMETER(P) (P) +#endif diff --git a/contrib/DirectX-Headers/include/wsl/wrladapter.h b/contrib/DirectX-Headers/include/wsl/wrladapter.h new file mode 100644 index 0000000..883ecab --- /dev/null +++ b/contrib/DirectX-Headers/include/wsl/wrladapter.h @@ -0,0 +1,801 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#include "winadapter.h" + +// defined by winadapter.h and needed by some windows headers, but conflicts +// with some libc++ implementation headers +#ifdef __in +#undef __in +#endif +#ifdef __out +#undef __out +#endif + +#include +#include +#include +#include +#include + +namespace Microsoft +{ +namespace WRL +{ + namespace Details + { + struct BoolStruct { int Member; }; + typedef int BoolStruct::* BoolType; + + template // T should be the ComPtr or a derived type of it, not just the interface + class ComPtrRefBase + { + public: + typedef typename T::InterfaceType InterfaceType; + + operator IUnknown**() const throw() + { + static_assert(__is_base_of(IUnknown, InterfaceType), "Invalid cast: InterfaceType does not derive from IUnknown"); + return reinterpret_cast(ptr_->ReleaseAndGetAddressOf()); + } + + protected: + T* ptr_; + }; + + template + class ComPtrRef : public Details::ComPtrRefBase // T should be the ComPtr or a derived type of it, not just the interface + { + using Super = Details::ComPtrRefBase; + using InterfaceType = typename Super::InterfaceType; + public: + ComPtrRef(_In_opt_ T* ptr) throw() + { + this->ptr_ = ptr; + } + + // Conversion operators + operator void**() const throw() + { + return reinterpret_cast(this->ptr_->ReleaseAndGetAddressOf()); + } + + // This is our operator ComPtr (or the latest derived class from ComPtr (e.g. WeakRef)) + operator T*() throw() + { + *this->ptr_ = nullptr; + return this->ptr_; + } + + // We define operator InterfaceType**() here instead of on ComPtrRefBase, since + // if InterfaceType is IUnknown or IInspectable, having it on the base will collide. + operator InterfaceType**() throw() + { + return this->ptr_->ReleaseAndGetAddressOf(); + } + + // This is used for IID_PPV_ARGS in order to do __uuidof(**(ppType)). + // It does not need to clear ptr_ at this point, it is done at IID_PPV_ARGS_Helper(ComPtrRef&) later in this file. + InterfaceType* operator *() throw() + { + return this->ptr_->Get(); + } + + // Explicit functions + InterfaceType* const * GetAddressOf() const throw() + { + return this->ptr_->GetAddressOf(); + } + + InterfaceType** ReleaseAndGetAddressOf() throw() + { + return this->ptr_->ReleaseAndGetAddressOf(); + } + }; + } + + template + class ComPtr + { + public: + typedef T InterfaceType; + + protected: + InterfaceType *ptr_; + template friend class ComPtr; + + void InternalAddRef() const throw() + { + if (ptr_ != nullptr) + { + ptr_->AddRef(); + } + } + + unsigned long InternalRelease() throw() + { + unsigned long ref = 0; + T* temp = ptr_; + + if (temp != nullptr) + { + ptr_ = nullptr; + ref = temp->Release(); + } + + return ref; + } + + public: + ComPtr() throw() : ptr_(nullptr) + { + } + + ComPtr(decltype(nullptr)) throw() : ptr_(nullptr) + { + } + + template + ComPtr(_In_opt_ U *other) throw() : ptr_(other) + { + InternalAddRef(); + } + + ComPtr(const ComPtr& other) throw() : ptr_(other.ptr_) + { + InternalAddRef(); + } + + // copy constructor that allows to instantiate class when U* is convertible to T* + template + ComPtr(const ComPtr &other, typename std::enable_if::value, void *>::type * = 0) throw() : + ptr_(other.ptr_) + { + InternalAddRef(); + } + + ComPtr(_Inout_ ComPtr &&other) throw() : ptr_(nullptr) + { + if (this != reinterpret_cast(&reinterpret_cast(other))) + { + Swap(other); + } + } + + // Move constructor that allows instantiation of a class when U* is convertible to T* + template + ComPtr(_Inout_ ComPtr&& other, typename std::enable_if::value, void *>::type * = 0) throw() : + ptr_(other.ptr_) + { + other.ptr_ = nullptr; + } + + ~ComPtr() throw() + { + InternalRelease(); + } + + ComPtr& operator=(decltype(nullptr)) throw() + { + InternalRelease(); + return *this; + } + + ComPtr& operator=(_In_opt_ T *other) throw() + { + if (ptr_ != other) + { + ComPtr(other).Swap(*this); + } + return *this; + } + + template + ComPtr& operator=(_In_opt_ U *other) throw() + { + ComPtr(other).Swap(*this); + return *this; + } + + ComPtr& operator=(const ComPtr &other) throw() + { + if (ptr_ != other.ptr_) + { + ComPtr(other).Swap(*this); + } + return *this; + } + + template + ComPtr& operator=(const ComPtr& other) throw() + { + ComPtr(other).Swap(*this); + return *this; + } + + ComPtr& operator=(_Inout_ ComPtr &&other) throw() + { + ComPtr(static_cast(other)).Swap(*this); + return *this; + } + + template + ComPtr& operator=(_Inout_ ComPtr&& other) throw() + { + ComPtr(static_cast&&>(other)).Swap(*this); + return *this; + } + + void Swap(_Inout_ ComPtr&& r) throw() + { + T* tmp = ptr_; + ptr_ = r.ptr_; + r.ptr_ = tmp; + } + + void Swap(_Inout_ ComPtr& r) throw() + { + T* tmp = ptr_; + ptr_ = r.ptr_; + r.ptr_ = tmp; + } + + operator Details::BoolType() const throw() + { + return Get() != nullptr ? &Details::BoolStruct::Member : nullptr; + } + + T* Get() const throw() + { + return ptr_; + } + + InterfaceType* operator->() const throw() + { + return ptr_; + } + + Details::ComPtrRef> operator&() throw() + { + return Details::ComPtrRef>(this); + } + + const Details::ComPtrRef> operator&() const throw() + { + return Details::ComPtrRef>(this); + } + + T* const* GetAddressOf() const throw() + { + return &ptr_; + } + + T** GetAddressOf() throw() + { + return &ptr_; + } + + T** ReleaseAndGetAddressOf() throw() + { + InternalRelease(); + return &ptr_; + } + + T* Detach() throw() + { + T* ptr = ptr_; + ptr_ = nullptr; + return ptr; + } + + void Attach(_In_opt_ InterfaceType* other) throw() + { + if (ptr_ != nullptr) + { + auto ref = ptr_->Release(); + // DBG_UNREFERENCED_LOCAL_VARIABLE(ref); + // Attaching to the same object only works if duplicate references are being coalesced. Otherwise + // re-attaching will cause the pointer to be released and may cause a crash on a subsequent dereference. + assert(ref != 0 || ptr_ != other); + } + + ptr_ = other; + } + + unsigned long Reset() + { + return InternalRelease(); + } + + // Previously, unsafe behavior could be triggered when 'this' is ComPtr or ComPtr and CopyTo is used to copy to another type U. + // The user will use operator& to convert the destination into a ComPtrRef, which can then implicit cast to IInspectable** and IUnknown**. + // If this overload of CopyTo is not present, it will implicitly cast to IInspectable or IUnknown and match CopyTo(InterfaceType**) instead. + // A valid polymoprhic downcast requires run-time type checking via QueryInterface, so CopyTo(InterfaceType**) will break type safety. + // This overload matches ComPtrRef before the implicit cast takes place, preventing the unsafe downcast. + template + HRESULT CopyTo(Details::ComPtrRef> ptr, typename std::enable_if< + (std::is_same::value) + && !std::is_same::value, void *>::type * = 0) const throw() + { + return ptr_->QueryInterface(uuidof(), ptr); + } + + HRESULT CopyTo(_Outptr_result_maybenull_ InterfaceType** ptr) const throw() + { + InternalAddRef(); + *ptr = ptr_; + return S_OK; + } + + HRESULT CopyTo(REFIID riid, _Outptr_result_nullonfailure_ void** ptr) const throw() + { + return ptr_->QueryInterface(riid, ptr); + } + + template + HRESULT CopyTo(_Outptr_result_nullonfailure_ U** ptr) const throw() + { + return ptr_->QueryInterface(uuidof(), reinterpret_cast(ptr)); + } + + // query for U interface + template + HRESULT As(_Inout_ Details::ComPtrRef> p) const throw() + { + return ptr_->QueryInterface(uuidof(), p); + } + + // query for U interface + template + HRESULT As(_Out_ ComPtr* p) const throw() + { + return ptr_->QueryInterface(uuidof(), reinterpret_cast(p->ReleaseAndGetAddressOf())); + } + + // query for riid interface and return as IUnknown + HRESULT AsIID(REFIID riid, _Out_ ComPtr* p) const throw() + { + return ptr_->QueryInterface(riid, reinterpret_cast(p->ReleaseAndGetAddressOf())); + } + + }; // ComPtr + + + namespace Details + { + // Empty struct used as default template parameter + class Nil + { + }; + + // Empty struct used for validating template parameter types in Implements + struct ImplementsBase + { + }; + + class RuntimeClassBase + { + protected: + template + static HRESULT AsIID(_In_ T* implements, REFIID riid, _Outptr_result_nullonfailure_ void **ppvObject) noexcept + { + *ppvObject = nullptr; + bool isRefDelegated = false; + // Prefer InlineIsEqualGUID over other forms since it's better perf on 4-byte aligned data, which is almost always the case. + if (InlineIsEqualGUID(riid, uuidof())) + { + *ppvObject = implements->CastToUnknown(); + static_cast(*ppvObject)->AddRef(); + return S_OK; + } + + HRESULT hr = implements->CanCastTo(riid, ppvObject, &isRefDelegated); + if (SUCCEEDED(hr) && !isRefDelegated) + { + static_cast(*ppvObject)->AddRef(); + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 6102) // '*ppvObject' is used but may not be initialized +#endif + _Analysis_assume_(SUCCEEDED(hr) || (*ppvObject == nullptr)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + return hr; + } + + public: + HRESULT RuntimeClassInitialize() noexcept + { + return S_OK; + } + }; + + // Interface traits provides casting and filling iids methods helpers + template + struct InterfaceTraits + { + typedef I0 Base; + + template + static Base* CastToBase(_In_ T* ptr) noexcept + { + return static_cast(ptr); + } + + template + static IUnknown* CastToUnknown(_In_ T* ptr) noexcept + { + return static_cast(static_cast(ptr)); + } + + template + _Success_(return == true) + static bool CanCastTo(_In_ T* ptr, REFIID riid, _Outptr_ void **ppv) noexcept + { + // Prefer InlineIsEqualGUID over other forms since it's better perf on 4-byte aligned data, which is almost always the case. + if (InlineIsEqualGUID(riid, uuidof())) + { + *ppv = static_cast(ptr); + return true; + } + + return false; + } + }; + + // Specialization for Nil parameter + template<> + struct InterfaceTraits + { + typedef Nil Base; + + template + _Success_(return == true) + static bool CanCastTo(_In_ T*, REFIID, _Outptr_ void **) noexcept + { + return false; + } + }; + + // ChainInterfaces - template allows specifying a derived COM interface along with its class hierarchy to allow QI for the base interfaces + template + struct ChainInterfaces : I0 + { + protected: + HRESULT CanCastTo(REFIID riid, _Outptr_ void **ppv) throw() + { + typename InterfaceTraits::Base* ptr = InterfaceTraits::CastToBase(this); + + return (InterfaceTraits::CanCastTo(this, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv) || + InterfaceTraits::CanCastTo(ptr, riid, ppv)) ? S_OK : E_NOINTERFACE; + } + + IUnknown* CastToUnknown() throw() + { + return InterfaceTraits::CastToUnknown(this); + } + }; + + // Helper template used by Implements. This template traverses a list of interfaces and adds them as base class and information + // to enable QI. + template + struct ImplementsHelper; + + template + struct ImplementsMarker + {}; + + template + struct MarkImplements; + + template + struct MarkImplements + { + typedef I0 Type; + }; + + template + struct MarkImplements + { + typedef ImplementsMarker Type; + }; + + // AdjustImplements pre-processes the type list for more efficient builds. + template + struct AdjustImplements; + + template + struct AdjustImplements + { + typedef ImplementsHelper::value>::Type, Bases...> Type; + }; + + // Use AdjustImplements to remove instances of "Nil" from the type list. + template + struct AdjustImplements + { + typedef typename AdjustImplements::Type Type; + }; + + template <> + struct AdjustImplements<> + { + typedef ImplementsHelper<> Type; + }; + + // Specialization handles unadorned interfaces + template + struct ImplementsHelper : + I0, + AdjustImplements::Type + { + template friend struct ImplementsHelper; + friend class RuntimeClassBase; + + protected: + + HRESULT CanCastTo(REFIID riid, _Outptr_ void **ppv, bool *pRefDelegated = nullptr) noexcept + { + // Prefer InlineIsEqualGUID over other forms since it's better perf on 4-byte aligned data, which is almost always the case. + if (InlineIsEqualGUID(riid, uuidof())) + { + *ppv = reinterpret_cast(reinterpret_cast(this)); + return S_OK; + } + return AdjustImplements::Type::CanCastTo(riid, ppv, pRefDelegated); + } + + IUnknown* CastToUnknown() noexcept + { + return reinterpret_cast(reinterpret_cast(this)); + } + }; + + + // Selector is used to "tag" base interfaces to be used in casting, since a runtime class may indirectly derive from + // the same interface or Implements<> template multiple times + template + struct Selector : public base + { + }; + + // Specialization handles types that derive from ImplementsHelper (e.g. nested Implements). + template + struct ImplementsHelper, TInterfaces...> : + Selector, TInterfaces...>>, + Selector::Type, ImplementsHelper, TInterfaces...>> + { + template friend struct ImplementsHelper; + friend class RuntimeClassBase; + + protected: + typedef Selector, TInterfaces...>> CurrentType; + typedef Selector::Type, ImplementsHelper, TInterfaces...>> BaseType; + + HRESULT CanCastTo(REFIID riid, _Outptr_ void **ppv, bool *pRefDelegated = nullptr) noexcept + { + HRESULT hr = CurrentType::CanCastTo(riid, ppv); + if (hr == E_NOINTERFACE) + { + hr = BaseType::CanCastTo(riid, ppv, pRefDelegated); + } + return hr; + } + + IUnknown* CastToUnknown() noexcept + { + // First in list wins. + return CurrentType::CastToUnknown(); + } + }; + + // terminal case specialization. + template <> + struct ImplementsHelper<> + { + template friend struct ImplementsHelper; + friend class RuntimeClassBase; + + protected: + HRESULT CanCastTo(_In_ REFIID /*riid*/, _Outptr_ void ** /*ppv*/, bool * /*pRefDelegated*/ = nullptr) noexcept + { + return E_NOINTERFACE; + } + + // IUnknown* CastToUnknown() noexcept; // not defined for terminal case. + }; + + // Specialization handles chaining interfaces + template + struct ImplementsHelper, TInterfaces...> : + ChainInterfaces, + AdjustImplements::Type + { + template friend struct ImplementsHelper; + friend class RuntimeClassBase; + + protected: + typedef typename AdjustImplements::Type BaseType; + + HRESULT CanCastTo(REFIID riid, _Outptr_ void **ppv, bool *pRefDelegated = nullptr) noexcept + { + HRESULT hr = ChainInterfaces::CanCastTo(riid, ppv); + if (FAILED(hr)) + { + hr = BaseType::CanCastTo(riid, ppv, pRefDelegated); + } + + return hr; + } + + IUnknown* CastToUnknown() noexcept + { + return ChainInterfaces::CastToUnknown(); + } + }; + + // Implements - template implementing QI using the information provided through its template parameters + // Each template parameter has to be one of the following: + // * COM Interface + // * A class that implements one or more COM interfaces + // * ChainInterfaces template + template + struct Implements : + AdjustImplements::Type, + ImplementsBase + { + public: + typedef I0 FirstInterface; + protected: + typedef typename AdjustImplements::Type BaseType; + template friend struct ImplementsHelper; + friend class RuntimeClassBase; + + HRESULT CanCastTo(REFIID riid, _Outptr_ void **ppv) noexcept + { + return BaseType::CanCastTo(riid, ppv); + } + + IUnknown* CastToUnknown() noexcept + { + return BaseType::CastToUnknown(); + } + }; + + // Used on RuntimeClass to protect it from being constructed with new + class DontUseNewUseMake + { + private: + void* operator new(size_t) noexcept + { + assert(false); + return 0; + } + + public: + void* operator new(size_t, _In_ void* placement) noexcept + { + return placement; + } + }; + + template + class RuntimeClassImpl : + public AdjustImplements::Type, + public RuntimeClassBase, + public DontUseNewUseMake + { + public: + STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppvObject) + { + return Super::AsIID(this, riid, ppvObject); + } + + STDMETHOD_(ULONG, AddRef)() + { + return InternalAddRef(); + } + + STDMETHOD_(ULONG, Release)() + { + ULONG ref = InternalRelease(); + if (ref == 0) + { + delete this; + } + + return ref; + } + + protected: + using Super = RuntimeClassBase; + static const LONG c_lProtectDestruction = -(LONG_MAX / 2); + + RuntimeClassImpl() noexcept = default; + + virtual ~RuntimeClassImpl() noexcept + { + // Set refcount_ to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + refcount_ = static_cast(c_lProtectDestruction); + } + + ULONG InternalAddRef() noexcept + { + return ++refcount_; + } + + ULONG InternalRelease() noexcept + { + return --refcount_; + } + + unsigned long GetRefCount() const noexcept + { + return refcount_; + } + + std::atomic refcount_{1}; + }; + } + + template + class Base : public Details::RuntimeClassImpl + { + Base(const Base&) = delete; + Base& operator=(const Base&) = delete; + + protected: + HRESULT CustomQueryInterface(REFIID /*riid*/, _Outptr_result_nullonfailure_ void** /*ppvObject*/, _Out_ bool *handled) + { + *handled = false; + return S_OK; + } + + public: + Base() throw() = default; + typedef Base RuntimeClassT; + }; + + // Creates a Nano-COM object wrapped in a smart pointer. + template + ComPtr Make(TArgs&&... args) + { + ComPtr object; + + std::unique_ptr buffer(new unsigned char[sizeof(T)]); + if (buffer) + { + T* ptr = new (buffer.get())T(std::forward(args)...); + object.Attach(ptr); + buffer.release(); + } + + return object; + } + + using Details::ChainInterfaces; +} +} + +// Overloaded global function to provide to IID_PPV_ARGS that support Details::ComPtrRef +template +void** IID_PPV_ARGS_Helper(Microsoft::WRL::Details::ComPtrRef pp) throw() +{ + return pp; +} \ No newline at end of file -- cgit v1.2.3