Kernelx Allocation impl + Logan/d3d11.x/etwplus stub

This commit is contained in:
Rodrigo Todescatto
2026-01-25 13:40:06 -03:00
parent 84afccff29
commit 4569273461
113 changed files with 57691 additions and 40 deletions

View File

@@ -1,16 +1,20 @@
cmake_minimum_required(VERSION 4.0)
project(WinDurango)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(projects/WinDurango.Common)
add_subdirectory(projects/WinDurango.Implementation.WinRT)
add_subdirectory(projects/WinDurango.WinRT)
add_subdirectory(projects/WinDurango.Kernel)
add_subdirectory("etwplus")
add_subdirectory("kernelx")
add_custom_target(WinDurango ALL DEPENDS
WinDurango.Common
WinDurango.Implementation.WinRT
WinDurango.WinRT
WinDurango.Kernel
etwplus
kernelx
)
add_subdirectory("d3d11.x")

15
CMakeSettings.json Normal file
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

6
d3d11.x/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
add_library(d3d11_x SHARED "d3d11.x.cpp" "d3d11.x.h" "unknown.g.h" "IGraphicsUnknown.h" "IGraphicsUnknown.cpp" "IIDExports.h" "IIDExports.cpp" "Exports.def")
target_link_options(d3d11_x
PUBLIC
$<$<CXX_COMPILER_ID:MSVC>:/FORCE:MULTIPLE>
)

8
d3d11.x/Exports.def Normal file
View File

@@ -0,0 +1,8 @@
LIBRARY d3d11_x
EXPORTS
IID_ID3D11DeviceContextX @40
IID_ID3D11DeviceX @41
IID_ID3D11Texture2D @61
IID_IDXGIFactory2 @76
IID_IDXGIDevice @70
IID_IDXGIDevice1 @71

View File

@@ -0,0 +1,29 @@
#include "IGraphicsUnknown.h"
//
// IUnknown
//
template<abi_t ABI>
HRESULT GraphicsUnknown<ABI>::QueryInterface(REFIID riid, void** ppvObject)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
template<abi_t ABI>
ULONG GraphicsUnknown<ABI>::AddRef()
{
IMPLEMENT_STUB();
return {};
}
template<abi_t ABI>
ULONG GraphicsUnknown<ABI>::Release()
{
IMPLEMENT_STUB();
return {};
}
#undef ABI_INTERFACE
#define ABI_INTERFACE(ABI) GraphicsUnknown<ABI>
D3D11_DECLARE_ABI_TEMPLATES();

View File

@@ -0,0 +1,18 @@
#pragma once
#include "d3d11.x.h"
template<abi_t ABI>
class GraphicsUnknown : public xbox::IGraphicsUnknown<ABI>
{
public:
//
// IUnknown
//
HRESULT QueryInterface(REFIID riid, void** ppvObject);
ULONG AddRef();
ULONG Release();
};
#undef ABI_INTERFACE
#define ABI_INTERFACE(ABI) GraphicsUnknown<ABI>
D3D11_DECLARE_ABI_TEMPLATES(extern);

19
d3d11.x/IIDExports.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "IIDExports.h"
DEFINE_GUID(IID_IPrivateData, 0x34DC21A0, 0x5DFC, 0x4C03, 0xB6, 0xA9, 0x8F, 0x75, 0x30, 0x5B, 0x85, 0xE6);
DEFINE_GUID(IID_IGraphicsUnknown, 0xACEEEA63, 0xE0A9, 0x4A1C, 0xBB, 0xEC, 0x71, 0xB2, 0xF4, 0x85, 0xF7, 0x58);
DEFINE_GUID(IID_ID3D11UserDefinedAnnotationX, 0xB2DAAD8B, 0x03D4, 0x4DBF, 0x95, 0xEB, 0x32, 0xAB, 0x4B, 0x63, 0xD0, 0xAB);
DEFINE_GUID(IID_ID3D11PIXPlaybackContextX, 0xC9225B7A, 0x4D50, 0x4EE0, 0x8E, 0x02, 0x28, 0x4D, 0x18, 0xF8, 0x39, 0x5D);
DEFINE_GUID(IID_ID3D11PerformanceDeviceX, 0x88671610, 0x712E, 0x4F1E, 0x84, 0xAB, 0x01, 0xB5, 0x94, 0x8B, 0xD3, 0x73);
DEFINE_GUID(IID_ID3D11PerformanceContextX, 0x9458FE06, 0xC78D, 0x47F7, 0x96, 0xA0, 0xEC, 0x7B, 0x72, 0x7B, 0xE1, 0xE9);
DEFINE_GUID(IID_ID3D11DmaEngineContextX, 0xA6332DDB, 0x8E02, 0x427D, 0xB0, 0xB7, 0x34, 0xA1, 0xE6, 0x1A, 0x64, 0x88);
DEFINE_GUID(IID_ID3D11DeviceX, 0x177700F9, 0x876A, 0x4436, 0xB3, 0x68, 0x36, 0xA6, 0x04, 0xF8, 0x2C, 0xEF);
DEFINE_GUID(IID_ID3D11Texture2D, 0x6f15AAF2, 0xD208, 0x4E89, 0x9A, 0xB4, 48, 95, 35, 0xD3, 0x4F, 0x9C);
DEFINE_GUID(IID_ID3D11DeviceContextX, 0x48800095, 0x7134, 0x4BE7, 0x91, 0x86, 0xb8, 0x6B, 0xEC, 0xB2, 64, 77);
DEFINE_GUID(IID_ID3D11CounterSetX, 0xF9F6A732, 0xC5F8, 0x4A57, 0xBA, 0x36, 0xEA, 0xE7, 0xC2, 0x7B, 0xA7, 0x4A);
DEFINE_GUID(IID_ID3D11CounterSampleX, 0x806CEEE4, 0x280B, 0x43D9, 0x90, 0x08, 0xB4, 0xFD, 0xF7, 0xFE, 0xBE, 0xE2);
DEFINE_GUID(IID_ID3D11Scratch, 0x758AE3BB, 0xEBEC, 0x4C81, 0x82, 0x7C, 0xEB, 0x9B, 0x7A, 0xCD, 0x57, 0x4A);
DEFINE_GUID(IID_ID2DPrivateInfo, 0xB79CC8DA, 0x337F, 0x400F, 0xB0, 0x9D, 0xB2, 0xED, 0xF8, 0xA8, 0x4E, 0x47);
DEFINE_GUID(IID_IDXGIFactory2, 0x50C83A1C, 0xE072, 0x4C48, 0x87, 0xB0, 0x36, 0x30, 0xFA, 0x36, 0xA6, 0xD0);
DEFINE_GUID(IID_IDXGIDevice, 0x54EC77FA, 0x1377, 0x44E6, 0x8C, 0x32, 0x88, 0xFD, 0x5F, 0x44, 0xC8, 0x4C);
DEFINE_GUID(IID_IDXGIDevice1, 0x77DB970F, 0x6276, 0x48BA, 0xBA, 0x28, 0x07, 0x01, 0x43, 0xB4, 0x39, 0x2C);

21
d3d11.x/IIDExports.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <d3d11.h>
#include <initguid.h>
extern const IID IID_IPrivateData;
extern const IID IID_IGraphicsUnknown;
extern const IID IID_ID3D11UserDefinedAnnotationX;
extern const IID IID_ID3D11PIXPlaybackContextX;
extern const IID IID_ID3D11PerformanceDeviceX;
extern const IID IID_ID3D11PerformanceContextX;
extern const IID IID_ID3D11DmaEngineContextX;
extern const IID IID_ID3D11DeviceX;
extern const IID IID_ID3D11Texture2D;
extern const IID IID_ID3D11DeviceContextX;
extern const IID IID_ID3D11CounterSetX;
extern const IID IID_ID3D11CounterSampleX;
extern const IID IID_ID3D11Scratch;
extern const IID IID_ID2DPrivateInfo;
extern const IID IID_IDXGIFactory2;
extern const IID IID_IDXGIDevice;
extern const IID IID_IDXGIDevice1;

170
d3d11.x/d3d11.x.cpp Normal file
View File

@@ -0,0 +1,170 @@
#include "d3d11.x.h"
#include "IIDExports.h"
EXTERN_C HRESULT __stdcall EraD3D10CreateBlob()
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall EraD3D11CreateDevice(void* pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
const D3D_FEATURE_LEVEL* pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
void** ppDevice,
D3D_FEATURE_LEVEL* pFeatureLevel,
void** ppImmediateContext)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall EraD3D11CreateDeviceAndSwapChain()
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
struct D3D11X_CREATE_DEVICE_PARAMETERS
{
UINT Version;
UINT Flags;
void* pOffchipTessellationBuffer;
void* pTessellationFactorsBuffer;
UINT DeferredDeletionThreadAffinityMask;
UINT ImmediateContextDeRingSizeBytes;
UINT ImmediateContextCeRingSizeBytes;
UINT ImmediateContextDeSegmentSizeBytes;
UINT ImmediateContextCeSegmentSizeBytes;
};
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceX(const D3D11X_CREATE_DEVICE_PARAMETERS* pParameters,
void** ppDevice,
void** ppImmediateContext)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceXAndSwapChain1(
const D3D11X_CREATE_DEVICE_PARAMETERS* pParameters,
const DXGI_SWAP_CHAIN_DESC1* pSwapChainDesc,
void** ppSwapChain,
void** ppDevice,
void** ppImmediateContext)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall D3DAllocateGraphicsMemory(SIZE_T dwSize, UINT64 a2, void* a3, int a4, void** a5)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall D3DConfigureVirtualMemory(UINT64 a1)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall D3DFreeGraphicsMemory(void* pAddress)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall D3DMapEsramMemory(UINT Flags, void* pVirtualAddress, UINT NumPages, const UINT* pPageList)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
struct DXGIX_FRAME_STATISTICS
{
UINT64 CPUTimePresentCalled;
UINT64 CPUTimeAddedToQueue;
UINT QueueLengthAddedToQueue;
UINT64 CPUTimeFrameComplete;
UINT64 GPUTimeFrameComplete;
UINT64 GPUCountTitleUsed;
UINT64 GPUCountSystemUsed;
UINT64 CPUTimeVSync;
UINT64 GPUTimeVSync;
UINT64 CPUTimeFlip;
UINT64 GPUTimeFlip;
UINT64 VSyncCount;
float PercentScanned;
void* Cookie[2];
};
EXTERN_C HRESULT __stdcall DXGIXGetFrameStatistics(UINT NumberFramesRequested, DXGIX_FRAME_STATISTICS* pFrameStatistics)
{
pFrameStatistics->QueueLengthAddedToQueue = 0;
pFrameStatistics->CPUTimeAddedToQueue = 0;
pFrameStatistics->CPUTimeFlip = 0;
pFrameStatistics->CPUTimeFrameComplete = 0;
pFrameStatistics->CPUTimePresentCalled = 0;
pFrameStatistics->CPUTimeVSync = 0;
pFrameStatistics->GPUCountSystemUsed = 0;
pFrameStatistics->GPUCountTitleUsed = 0;
pFrameStatistics->GPUTimeFlip = 0;
pFrameStatistics->GPUTimeFrameComplete = 0;
pFrameStatistics->GPUTimeVSync = 0;
pFrameStatistics->PercentScanned = 100.0f;
pFrameStatistics->QueueLengthAddedToQueue = 0;
pFrameStatistics->VSyncCount = 0;
return S_OK;
}
struct DXGIX_PRESENTARRAY_PARAMETERS
{
BOOL Disable;
BOOL UsePreviousBuffer;
D3D11_RECT SourceRect;
POINT DestRectUpperLeft;
FLOAT ScaleFactorVert;
FLOAT ScaleFactorHorz;
void* Cookie;
UINT Flags;
};
void PresentArray(UINT NumSwapChains, void** SwapChains, UINT SyncInterval)
{
//TODO
}
EXTERN_C HRESULT __stdcall DXGIXPresentArray(UINT SyncInterval,
UINT PresentImmediateThreshold,
UINT Flags,
UINT NumSwapChains,
void** ppSwapChains,
const DXGIX_PRESENTARRAY_PARAMETERS* pPresentParameters)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
EXTERN_C HRESULT __stdcall DXGIXSetVLineNotification(UINT VLineCounter, UINT VLineNum, HANDLE hEvent)
{
IMPLEMENT_STUB();
return E_NOTIMPL;
}
#pragma comment(linker, "/export:D3D10CreateBlob=EraD3D10CreateBlob,@1")
#pragma comment(linker, "/export:D3D11CreateDevice=EraD3D11CreateDevice,@2")
#pragma comment(linker, "/export:D3D11CreateDeviceAndSwapChain=EraD3D11CreateDeviceAndSwapChain,@3")
#pragma comment(linker, "/export:D3D11XCreateDeviceX,@4")
#pragma comment(linker, "/export:D3D11XCreateDeviceXAndSwapChain1,@5")
#pragma comment(linker, "/export:D3DAllocateGraphicsMemory,@6")
#pragma comment(linker, "/export:D3DConfigureVirtualMemory,@7")
#pragma comment(linker, "/export:D3DFreeGraphicsMemory,@8")
#pragma comment(linker, "/export:D3DMapEsramMemory,@9")
#pragma comment(linker, "/export:DXGIXGetFrameStatistics,@10")
#pragma comment(linker, "/export:DXGIXPresentArray,@11")
#pragma comment(linker, "/export:DXGIXSetVLineNotification,@12")

63
d3d11.x/d3d11.x.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment (lib, "version.lib")
#include <d3d11_4.h>
#include <dxgi1_6.h>
#include "xcom/base.h"
#include <Windows.h>
#include <bitset>
#include <map>
#include "unknown.g.h"
#include <mutex>
//We use that to know the OS version.
abi_t g_ABI{};
//Immediate Context fence object.
BOOL m_Fence = TRUE;
//Multimap for placement update
std::multimap<void*, void*> g_ResourceMap;
std::mutex g_ResourceMapMutex;
#pragma comment(lib, "onecore.lib")
#pragma comment(lib, "kernel32.lib")
void GetCombaseVersion()
{
DWORD FileVersionSize = GetFileVersionInfoSizeW(L".\\EmbeddedXvd\\Windows\\System32\\combase.dll", NULL);
if (!FileVersionSize)
{
MessageBoxW(nullptr, L"Couldn't get the combase version info size! Make sure you have EmbeddedXvd in the game root/Mount folder.", L"D3D11.X Error!", MB_OK);
}
BYTE* Data = new BYTE[FileVersionSize];
BOOL ret = GetFileVersionInfoW(L".\\EmbeddedXvd\\Windows\\System32\\combase.dll", NULL, FileVersionSize, Data);
if (!ret)
{
MessageBoxW(nullptr, L"Couldn't get the combase version info! Make sure you have EmbeddedXvd in the game root/Mount folder.", L"D3D11.X Error!", MB_OK);
delete[] Data;
}
VS_FIXEDFILEINFO* pFixedFileInfo{};
UINT Length = 0;
VerQueryValueW(Data, L"\\", (LPVOID*)&pFixedFileInfo, &Length);
if (!pFixedFileInfo)
{
MessageBoxW(nullptr, L"Couldn't get the combase version value! Make sure you have EmbeddedXvd in the game root/Mount folder.", L"D3D11.X Error!", MB_OK);
delete[] Data;
}
DWORD major = HIWORD(pFixedFileInfo->dwProductVersionMS);
DWORD minor = LOWORD(pFixedFileInfo->dwProductVersionMS);
DWORD build = HIWORD(pFixedFileInfo->dwProductVersionLS);
DWORD revision = LOWORD(pFixedFileInfo->dwProductVersionLS);
g_ABI.Major = major;
g_ABI.Minor = minor;
g_ABI.Build = build;
g_ABI.Revision = revision;
}

86
d3d11.x/unknown.g.h Normal file
View File

@@ -0,0 +1,86 @@
#pragma once
#ifndef __unknown_g_h__
#define __unknown_g_h__
#include "xcom/base.h"
namespace xbox
{
template<abi_t ABI>
struct IGraphicsUnknown;
template<abi_t ABI>
struct IGraphicsUnknownVtbl;
template<abi_t ABI>
struct __declspec(uuid("bcfaae29-e1a2-4b9a-aafc-55b9ff21fa54")) IGraphicsUnwrap;
template<abi_t ABI>
struct IGraphicsUnwrapVtbl;
namespace details
{
template<abi_t ABI>
struct IGraphicsUnknownData
{
ULONG m_RefCount;
};
template<abi_t ABI>
requires (ABI >= abi_t{ 10,0,14393,2152 } && ABI < abi_t{ 10,0,19041,3453 })
struct IGraphicsUnknownData<ABI>
{
ULONG m_DeviceIndex : 3;
ULONG m_PrivateDataPresent : 1;
ULONG m_Reserved : 28;
ULONG m_RefCount;
};
template<abi_t ABI>
requires (ABI >= abi_t{ 10,0,19041,3453 })
struct IGraphicsUnknownData<ABI>
{
ULONG m_DeviceIndex : 3;
ULONG m_PrivateDataPresent : 1;
ULONG m_DisableCollectiveRefCount : 1;
ULONG m_Reserved : 27;
ULONG m_RefCount;
};
}
template<abi_t ABI>
struct IGraphicsUnknown : details::IGraphicsUnknownData<ABI>
{
virtual HRESULT QueryInterface(REFIID riid, void** ppvObject) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
template<abi_t ABI>
struct IGraphicsUnknownVtbl
{
HRESULT(*QueryInterface)(void*, REFIID riid, void** ppvObject);
ULONG(*AddRef)(void*);
ULONG(*Release)(void*);
};
template<abi_t ABI>
struct IGraphicsUnwrap
{
};
template<abi_t ABI>
struct IGraphicsUnwrapVtbl
{
};
}
DECLARE_ABI_UUIDOF_HELPER(xbox::IGraphicsUnknown, 0xACEEEA63, 0xE0A9, 0x4A1C, 0xBB, 0xEC, 0x71, 0xB2, 0xF4, 0x85, 0xF7, 0x58)
DECLARE_ABI_UUIDOF_HELPER(xbox::IGraphicsUnwrap, 0xBCFAAE29, 0xE1A2, 0x4B9A, 0xAA, 0xFC, 0x55, 0xB9, 0xFF, 0x21, 0xFA, 0x54)
#define D3D11_DECLARE_ABI_TEMPLATES(prefix) \
prefix template class ABI_INTERFACE((abi_t{0,0,0,0})); \
prefix template class ABI_INTERFACE((abi_t{10,0,14393,2152})); \
prefix template class ABI_INTERFACE((abi_t{10,0,19041,3453}))
#endif // __unknown_g_h__

6709
d3d11.x/wil/Tracelogging.h Normal file

File diff suppressed because it is too large Load Diff

3452
d3d11.x/wil/com.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,489 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Smart pointers and other thin usability pattern wrappers over COM patterns.
#ifndef __WIL_COM_APARTMENT_VARIABLE_INCLUDED
#define __WIL_COM_APARTMENT_VARIABLE_INCLUDED
#include <any>
#include <objidl.h>
#include <roapi.h>
#include <type_traits>
#include <unordered_map>
#include <winrt/Windows.Foundation.h>
#include "com.h"
#include "cppwinrt.h"
#include "result_macros.h"
#include "win32_helpers.h"
#ifndef WIL_ENABLE_EXCEPTIONS
#error This header requires exceptions
#endif
namespace wil
{
// Determine if apartment variables are supported in the current process context.
// Prior to build 22365, the APIs needed to create apartment variables (e.g. RoGetApartmentIdentifier)
// failed for unpackaged processes. For MS people, see http://task.ms/31861017 for details.
// APIs needed to implement apartment variables did not work in non-packaged processes.
inline bool are_apartment_variables_supported()
{
unsigned long long apartmentId{};
return RoGetApartmentIdentifier(&apartmentId) != HRESULT_FROM_WIN32(ERROR_API_UNAVAILABLE);
}
// COM will implicitly rundown the apartment registration when it invokes a handler
// and blocks calling unregister when executing the callback. So be careful to release()
// this when callback is invoked to avoid a double free of the cookie.
using unique_apartment_shutdown_registration =
unique_any<APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, decltype(&::RoUnregisterForApartmentShutdown), ::RoUnregisterForApartmentShutdown>;
struct apartment_variable_platform
{
static unsigned long long GetApartmentId()
{
unsigned long long apartmentId{};
FAIL_FAST_IF_FAILED(RoGetApartmentIdentifier(&apartmentId));
return apartmentId;
}
static auto RegisterForApartmentShutdown(IApartmentShutdown* observer)
{
unsigned long long id{};
shutdown_type cookie;
THROW_IF_FAILED(RoRegisterForApartmentShutdown(observer, &id, cookie.put()));
return cookie;
}
static void UnRegisterForApartmentShutdown(APARTMENT_SHUTDOWN_REGISTRATION_COOKIE cookie)
{
FAIL_FAST_IF_FAILED(RoUnregisterForApartmentShutdown(cookie));
}
static auto CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/)
{
return wil::CoInitializeEx(coinitFlags);
}
// disable the test hook
inline static constexpr unsigned long AsyncRundownDelayForTestingRaces = INFINITE;
using shutdown_type = wil::unique_apartment_shutdown_registration;
};
enum class apartment_variable_leak_action
{
fail_fast,
ignore
};
// "pins" the current module in memory by incrementing the module reference count and leaking that.
inline void ensure_module_stays_loaded()
{
static INIT_ONCE s_initLeakModule{}; // avoiding magic statics
wil::init_once_failfast(s_initLeakModule, []() {
HMODULE result{};
FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"", &result));
return S_OK;
});
}
/// @cond
namespace details
{
// For the address of data, you can detect global variables by the ability to resolve the module from the address.
inline bool IsGlobalVariable(const void* moduleAddress) noexcept
{
wil::unique_hmodule moduleHandle;
return GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<PCWSTR>(moduleAddress), &moduleHandle) != FALSE;
}
struct any_maker_base
{
std::any (*adapter)(void*);
void* inner;
WI_NODISCARD std::any operator()() const
{
return adapter(inner);
}
};
template <typename T>
struct any_maker : any_maker_base
{
any_maker()
{
adapter = [](auto) -> std::any {
return T{};
};
}
any_maker(T (*maker)())
{
adapter = [](auto maker) -> std::any {
return reinterpret_cast<T (*)()>(maker)();
};
inner = reinterpret_cast<void*>(maker);
}
template <typename F>
any_maker(F&& f)
{
adapter = [](auto maker) -> std::any {
return reinterpret_cast<F*>(maker)[0]();
};
inner = std::addressof(f);
}
};
template <apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast, typename test_hook = apartment_variable_platform>
struct apartment_variable_base
{
inline static winrt::slim_mutex s_lock;
struct apartment_variable_storage
{
apartment_variable_storage(apartment_variable_storage&& other) noexcept = default;
apartment_variable_storage(const apartment_variable_storage& other) = delete;
apartment_variable_storage(typename test_hook::shutdown_type&& cookie_) : cookie(std::move(cookie_))
{
}
winrt::apartment_context context;
typename test_hook::shutdown_type cookie;
// Variables are stored using the address of the apartment_variable_base<> as the key.
std::unordered_map<apartment_variable_base<leak_action, test_hook>*, std::any> variables;
};
// Apartment id -> variables storage.
inline static wil::object_without_destructor_on_shutdown<std::unordered_map<unsigned long long, apartment_variable_storage>> s_apartmentStorage;
constexpr apartment_variable_base() = default;
~apartment_variable_base()
{
// Global variables (object with static storage duration)
// are run down when the process is shutting down or when the
// dll is unloaded. At these points it is not possible to start
// an async operation and the work performed is not needed,
// the apartments with variable have been run down already.
const auto isGlobal = details::IsGlobalVariable(this);
if (!isGlobal)
{
clear_all_apartments_async();
}
if constexpr (leak_action == apartment_variable_leak_action::fail_fast)
{
if (isGlobal && !ProcessShutdownInProgress())
{
// If you hit this fail fast it means the storage in s_apartmentStorage will be leaked.
// For apartment variables used in .exes, this is expected and
// this fail fast should be disabled using
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
//
// For DLLs, if this is expected, disable this fail fast using
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
//
// Use of apartment variables in DLLs only loaded by COM will never hit this case
// as COM will unload DLLs before apartments are rundown,
// providing the opportunity to empty s_apartmentStorage.
//
// But DLLs loaded and unloaded to call DLL entry points (outside of COM) may
// create variable storage that can't be cleaned up as the DLL lifetime is
// shorter that the COM lifetime. In these cases either
// 1) accept the leaks and disable the fail fast as describe above
// 2) disable module unloading by calling wil::ensure_module_stays_loaded
// 3) CoCreate an object from this DLL to make COM aware of the DLL
FAIL_FAST_IF(!s_apartmentStorage.get().empty());
}
}
}
// non-copyable, non-assignable
apartment_variable_base(apartment_variable_base const&) = delete;
void operator=(apartment_variable_base const&) = delete;
// get current value or throw if no value has been set
std::any& get_existing()
{
auto any = get_if();
if (!any)
{
THROW_HR(E_NOT_SET);
}
return *any;
}
static apartment_variable_storage* get_current_apartment_variable_storage()
{
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
if (storage != s_apartmentStorage.get().end())
{
return &storage->second;
}
return nullptr;
}
apartment_variable_storage* ensure_current_apartment_variables()
{
auto variables = get_current_apartment_variable_storage();
if (variables)
{
return variables;
}
struct ApartmentObserver : public winrt::implements<ApartmentObserver, IApartmentShutdown>
{
void STDMETHODCALLTYPE OnUninitialize(unsigned long long apartmentId) noexcept override
{
// This code runs at apartment rundown so be careful to avoid deadlocks by
// extracting the variables under the lock then release them outside.
auto variables = [apartmentId]() {
auto lock = winrt::slim_lock_guard(s_lock);
return s_apartmentStorage.get().extract(apartmentId);
}();
WI_ASSERT(variables.key() == apartmentId);
// The system implicitly releases the shutdown observer
// after invoking the callback and does not allow calling unregister
// in the callback. So release the reference to the registration.
variables.mapped().cookie.release();
}
};
auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().get());
return &s_apartmentStorage.get()
.insert({test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration))})
.first->second;
}
// get current value or custom-construct one on demand
template <typename T>
std::any& get_or_create(any_maker<T>&& creator)
{
apartment_variable_storage* variable_storage = nullptr;
{ // scope for lock
auto lock = winrt::slim_lock_guard(s_lock);
variable_storage = ensure_current_apartment_variables();
auto variable = variable_storage->variables.find(this);
if (variable != variable_storage->variables.end())
{
return variable->second;
}
} // drop the lock
// create the object outside the lock to avoid reentrant deadlock
auto value = creator();
auto insert_lock = winrt::slim_lock_guard(s_lock);
// The insertion may fail if creator() recursively caused itself to be created,
// in which case we return the existing object and the falsely-created one is discarded.
return variable_storage->variables.insert({this, std::move(value)}).first->second;
}
// get pointer to current value or nullptr if no value has been set
std::any* get_if()
{
auto lock = winrt::slim_lock_guard(s_lock);
if (auto variable_storage = get_current_apartment_variable_storage())
{
auto variable = variable_storage->variables.find(this);
if (variable != variable_storage->variables.end())
{
return &(variable->second);
}
}
return nullptr;
}
// replace or create the current value, fail fasts if the value is not already stored
void set(std::any value)
{
// release value, with the swapped value, outside of the lock
{
auto lock = winrt::slim_lock_guard(s_lock);
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
FAIL_FAST_IF(storage == s_apartmentStorage.get().end());
auto& variable_storage = storage->second;
auto variable = variable_storage.variables.find(this);
FAIL_FAST_IF(variable == variable_storage.variables.end());
variable->second.swap(value);
}
}
// remove any current value
void clear()
{
auto lock = winrt::slim_lock_guard(s_lock);
if (auto variable_storage = get_current_apartment_variable_storage())
{
variable_storage->variables.erase(this);
if (variable_storage->variables.size() == 0)
{
s_apartmentStorage.get().erase(test_hook::GetApartmentId());
}
}
}
winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async()
{
// gather all the apartments that hold objects we need to destruct
// (do not gather the objects themselves, because the apartment might
// destruct before we get around to it, and we should let the apartment
// destruct the object while it still can).
std::vector<winrt::apartment_context> contexts;
{ // scope for lock
auto lock = winrt::slim_lock_guard(s_lock);
for (auto& [id, storage] : s_apartmentStorage.get())
{
auto variable = storage.variables.find(this);
if (variable != storage.variables.end())
{
contexts.push_back(storage.context);
}
}
}
if (contexts.empty())
{
co_return;
}
wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup
FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put()));
// From a background thread hop into each apartment to run down the object
// if it's still there.
co_await winrt::resume_background();
// This hook enables testing the case where execution of this method loses the race with
// apartment rundown by other means.
if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE)
{
Sleep(test_hook::AsyncRundownDelayForTestingRaces);
}
for (auto&& context : contexts)
{
try
{
co_await context;
clear();
}
catch (winrt::hresult_error const& e)
{
// Ignore failure if apartment ran down before we could clean it up.
// The object already ran down as part of apartment cleanup.
if ((e.code() != RPC_E_SERVER_DIED_DNE) && (e.code() != RPC_E_DISCONNECTED))
{
throw;
}
}
catch (...)
{
FAIL_FAST();
}
}
}
static const auto& storage()
{
return s_apartmentStorage.get();
}
static size_t current_apartment_variable_count()
{
auto lock = winrt::slim_lock_guard(s_lock);
if (auto variable_storage = get_current_apartment_variable_storage())
{
return variable_storage->variables.size();
}
return 0;
}
};
} // namespace details
/// @endcond
// Apartment variables enable storing COM objects safely in globals
// (objects with static storage duration) by creating a unique copy
// in each apartment and managing their lifetime based on apartment rundown
// notifications.
// They can also be used for automatic or dynamic storage duration but those
// cases are less common.
// This type is also useful for storing references to apartment affine objects.
//
// Note, that apartment variables hosted in a COM DLL need to integrate with
// the DllCanUnloadNow() function to include the ref counts contributed by
// C++ WinRT objects. This is automatic for DLLs that host C++ WinRT objects
// but WRL projects will need to be updated to call winrt::get_module_lock().
template <typename T, apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast, typename test_hook = wil::apartment_variable_platform>
struct apartment_variable : details::apartment_variable_base<leak_action, test_hook>
{
using base = details::apartment_variable_base<leak_action, test_hook>;
constexpr apartment_variable() = default;
// Get current value or throw if no value has been set.
T& get_existing()
{
return std::any_cast<T&>(base::get_existing());
}
// Get current value or default-construct one on demand.
T& get_or_create()
{
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>()));
}
// Get current value or custom-construct one on demand.
template <typename F>
T& get_or_create(F&& f)
{
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>(std::forward<F>(f))));
}
// get pointer to current value or nullptr if no value has been set
T* get_if()
{
return std::any_cast<T>(base::get_if());
}
// replace or create the current value, fail fasts if the value is not already stored
template <typename V>
void set(V&& value)
{
return base::set(std::forward<V>(value));
}
// Clear the value in the current apartment.
using base::clear;
// Asynchronously clear the value in all apartments it is present in.
using base::clear_all_apartments_async;
// For testing only.
// 1) To observe the state of the storage in the debugger assign this to
// a temporary variable (const&) and watch its contents.
// 2) Use this to test the implementation.
using base::storage;
// For testing only. The number of variables in the current apartment.
using base::current_apartment_variable_count;
};
} // namespace wil
#endif // __WIL_COM_APARTMENT_VARIABLE_INCLUDED

920
d3d11.x/wil/common.h Normal file
View File

@@ -0,0 +1,920 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Common Helpers: Provides broadly applicable, dependency-free pure C++ helpers, macros and type traits.
#ifndef __WIL_COMMON_INCLUDED
#define __WIL_COMMON_INCLUDED
#if defined(_KERNEL_MODE) && !defined(__WIL_MIN_KERNEL)
// This define indicates that the WIL usage is in a kernel mode context where
// a high degree of WIL functionality is desired.
//
// Use (sparingly) to change behavior based on whether WIL is being used in kernel
// mode or user mode.
#define WIL_KERNEL_MODE
#endif
// Defining WIL_HIDE_DEPRECATED will hide everything deprecated.
// Each wave of deprecation will add a new WIL_HIDE_DEPRECATED_YYMM number that can be used to lock deprecation at
// a particular point, allowing components to avoid backslide and catch up to the current independently.
/// @cond
#ifdef WIL_HIDE_DEPRECATED
#define WIL_HIDE_DEPRECATED_1809
#endif
#ifdef WIL_HIDE_DEPRECATED_1809
#define WIL_HIDE_DEPRECATED_1612
#endif
#ifdef WIL_HIDE_DEPRECATED_1612
#define WIL_HIDE_DEPRECATED_1611
#endif
/// @endcond
// Implementation side note: ideally the deprecation would be done with the function-level declspec
// as it allows you to utter the error text when used. The declspec works, but doing it selectively with
// a macro makes intellisense deprecation comments not work. So we just use the #pragma deprecation.
/// @cond
#ifdef WIL_WARN_DEPRECATED
#define WIL_WARN_DEPRECATED_1809
#endif
#ifdef WIL_WARN_DEPRECATED_1809
#define WIL_WARN_DEPRECATED_1612
#endif
#ifdef WIL_WARN_DEPRECATED_1612
#define WIL_WARN_DEPRECATED_1611
#endif
#ifdef WIL_WARN_DEPRECATED_1809
#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
#else
#define WIL_WARN_DEPRECATED_1809_PRAGMA(...)
#endif
#ifdef WIL_WARN_DEPRECATED_1611
#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
#else
#define WIL_WARN_DEPRECATED_1611_PRAGMA(...)
#endif
#ifdef WIL_WARN_DEPRECATED_1612
#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) __pragma(deprecated(__VA_ARGS__))
#else
#define WIL_WARN_DEPRECATED_1612_PRAGMA(...)
#endif
/// @endcond
/// @cond
#if defined(_MSVC_LANG)
#define __WI_SUPPRESS_BREAKING_WARNINGS_S __pragma(warning(push)) __pragma(warning(disable : 4127 26498 4245 26814))
#define __WI_SUPPRESS_BREAKING_WARNINGS_E __pragma(warning(pop))
#define __WI_SUPPRESS_NULLPTR_ANALYSIS __pragma(warning(suppress : 28285 6504))
#define __WI_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress : 26495))
#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress : 26439))
#else
#define __WI_SUPPRESS_BREAKING_WARNINGS_S
#define __WI_SUPPRESS_BREAKING_WARNINGS_E
#define __WI_SUPPRESS_NULLPTR_ANALYSIS
#define __WI_SUPPRESS_NONINIT_ANALYSIS
#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS
#endif
/// @endcond
#include <sal.h>
// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can
// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to
// basic macros without the function for common use cases.
/// @cond
#define _Success_return_ _Success_(return)
#define _Success_true_ _Success_(true)
#define __declspec_noinline_ __declspec(noinline)
#define __declspec_selectany_ __declspec(selectany)
/// @endcond
//! @defgroup macrobuilding Macro Composition
//! The following macros are building blocks primarily intended for authoring other macros.
//! @{
//! Re-state a macro value (indirection for composition)
#define WI_FLATTEN(...) __VA_ARGS__
/// @cond
#define __WI_PASTE_imp(a, b) a##b
/// @endcond
//! This macro is for use in other macros to paste two tokens together, such as a constant and the __LINE__ macro.
#define WI_PASTE(a, b) __WI_PASTE_imp(a, b)
/// @cond
#define __WI_HAS_VA_OPT_IMPL(F, T, ...) T
#define __WI_HAS_VA_OPT_(...) __WI_HAS_VA_OPT_IMPL(__VA_OPT__(0, ) 1, 0)
/// @endcond
//! Evaluates to '1' when support for '__VA_OPT__' is available, else '0'
#define WI_HAS_VA_OPT __WI_HAS_VA_OPT_(unused)
/// @cond
// clang-format off
#define __WI_ARGS_COUNT1(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, \
A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, \
A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, \
A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, count, ...) count
#define __WI_ARGS_COUNT0(...) WI_FLATTEN(__WI_ARGS_COUNT1(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \
79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define __WI_ARGS_COUNT_PREFIX(...) 0, __VA_ARGS__
// clang-format on
/// @endcond
//! This variadic macro returns the number of arguments passed to it (up to 99).
#if WI_HAS_VA_OPT
#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(0 __VA_OPT__(, __VA_ARGS__))
#else
#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(__WI_ARGS_COUNT_PREFIX(__VA_ARGS__))
#endif
/// @cond
#define __WI_FOR_imp0(fn)
#define __WI_FOR_imp1(fn, arg) fn(arg)
#define __WI_FOR_imp2(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp1(fn, __VA_ARGS__))
#define __WI_FOR_imp3(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp2(fn, __VA_ARGS__))
#define __WI_FOR_imp4(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp3(fn, __VA_ARGS__))
#define __WI_FOR_imp5(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp4(fn, __VA_ARGS__))
#define __WI_FOR_imp6(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp5(fn, __VA_ARGS__))
#define __WI_FOR_imp7(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp6(fn, __VA_ARGS__))
#define __WI_FOR_imp8(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp7(fn, __VA_ARGS__))
#define __WI_FOR_imp9(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp8(fn, __VA_ARGS__))
#define __WI_FOR_imp10(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp9(fn, __VA_ARGS__))
#define __WI_FOR_imp11(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp10(fn, __VA_ARGS__))
#define __WI_FOR_imp12(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp11(fn, __VA_ARGS__))
#define __WI_FOR_imp13(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp12(fn, __VA_ARGS__))
#define __WI_FOR_imp14(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp13(fn, __VA_ARGS__))
#define __WI_FOR_imp15(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp14(fn, __VA_ARGS__))
#define __WI_FOR_imp16(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp15(fn, __VA_ARGS__))
#define __WI_FOR_imp17(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp16(fn, __VA_ARGS__))
#define __WI_FOR_imp18(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp17(fn, __VA_ARGS__))
#define __WI_FOR_imp19(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp18(fn, __VA_ARGS__))
#define __WI_FOR_imp20(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp19(fn, __VA_ARGS__))
#define __WI_FOR_imp21(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp20(fn, __VA_ARGS__))
#define __WI_FOR_imp22(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp21(fn, __VA_ARGS__))
#define __WI_FOR_imp23(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp22(fn, __VA_ARGS__))
#define __WI_FOR_imp24(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp23(fn, __VA_ARGS__))
#define __WI_FOR_imp25(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp24(fn, __VA_ARGS__))
#define __WI_FOR_imp26(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp25(fn, __VA_ARGS__))
#define __WI_FOR_imp27(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp26(fn, __VA_ARGS__))
#define __WI_FOR_imp28(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp27(fn, __VA_ARGS__))
#define __WI_FOR_imp29(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp28(fn, __VA_ARGS__))
#define __WI_FOR_imp30(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp29(fn, __VA_ARGS__))
#define __WI_FOR_imp31(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp30(fn, __VA_ARGS__))
#define __WI_FOR_imp32(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp31(fn, __VA_ARGS__))
#define __WI_FOR_imp33(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp32(fn, __VA_ARGS__))
#define __WI_FOR_imp34(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp33(fn, __VA_ARGS__))
#define __WI_FOR_imp35(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp34(fn, __VA_ARGS__))
#define __WI_FOR_imp36(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp35(fn, __VA_ARGS__))
#define __WI_FOR_imp37(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp36(fn, __VA_ARGS__))
#define __WI_FOR_imp38(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp37(fn, __VA_ARGS__))
#define __WI_FOR_imp39(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp38(fn, __VA_ARGS__))
#define __WI_FOR_imp40(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp39(fn, __VA_ARGS__))
#define __WI_FOR_imp41(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp40(fn, __VA_ARGS__))
#define __WI_FOR_imp42(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp41(fn, __VA_ARGS__))
#define __WI_FOR_imp43(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp42(fn, __VA_ARGS__))
#define __WI_FOR_imp44(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp43(fn, __VA_ARGS__))
#define __WI_FOR_imp45(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp44(fn, __VA_ARGS__))
#define __WI_FOR_imp46(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp45(fn, __VA_ARGS__))
#define __WI_FOR_imp47(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp46(fn, __VA_ARGS__))
#define __WI_FOR_imp48(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp47(fn, __VA_ARGS__))
#define __WI_FOR_imp49(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp48(fn, __VA_ARGS__))
#define __WI_FOR_imp50(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp49(fn, __VA_ARGS__))
#define __WI_FOR_imp51(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp50(fn, __VA_ARGS__))
#define __WI_FOR_imp52(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp51(fn, __VA_ARGS__))
#define __WI_FOR_imp53(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp52(fn, __VA_ARGS__))
#define __WI_FOR_imp54(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp53(fn, __VA_ARGS__))
#define __WI_FOR_imp55(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp54(fn, __VA_ARGS__))
#define __WI_FOR_imp56(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp55(fn, __VA_ARGS__))
#define __WI_FOR_imp57(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp56(fn, __VA_ARGS__))
#define __WI_FOR_imp58(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp57(fn, __VA_ARGS__))
#define __WI_FOR_imp59(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp58(fn, __VA_ARGS__))
#define __WI_FOR_imp60(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp59(fn, __VA_ARGS__))
#define __WI_FOR_imp61(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp60(fn, __VA_ARGS__))
#define __WI_FOR_imp62(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp61(fn, __VA_ARGS__))
#define __WI_FOR_imp63(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp62(fn, __VA_ARGS__))
#define __WI_FOR_imp64(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp63(fn, __VA_ARGS__))
#define __WI_FOR_imp65(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp64(fn, __VA_ARGS__))
#define __WI_FOR_imp66(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp65(fn, __VA_ARGS__))
#define __WI_FOR_imp67(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp66(fn, __VA_ARGS__))
#define __WI_FOR_imp68(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp67(fn, __VA_ARGS__))
#define __WI_FOR_imp69(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp68(fn, __VA_ARGS__))
#define __WI_FOR_imp70(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp69(fn, __VA_ARGS__))
#define __WI_FOR_imp71(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp70(fn, __VA_ARGS__))
#define __WI_FOR_imp72(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp71(fn, __VA_ARGS__))
#define __WI_FOR_imp73(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp72(fn, __VA_ARGS__))
#define __WI_FOR_imp74(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp73(fn, __VA_ARGS__))
#define __WI_FOR_imp75(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp74(fn, __VA_ARGS__))
#define __WI_FOR_imp76(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp75(fn, __VA_ARGS__))
#define __WI_FOR_imp77(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp76(fn, __VA_ARGS__))
#define __WI_FOR_imp78(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp77(fn, __VA_ARGS__))
#define __WI_FOR_imp79(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp78(fn, __VA_ARGS__))
#define __WI_FOR_imp80(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp79(fn, __VA_ARGS__))
#define __WI_FOR_imp81(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp80(fn, __VA_ARGS__))
#define __WI_FOR_imp82(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp81(fn, __VA_ARGS__))
#define __WI_FOR_imp83(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp82(fn, __VA_ARGS__))
#define __WI_FOR_imp84(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp83(fn, __VA_ARGS__))
#define __WI_FOR_imp85(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp84(fn, __VA_ARGS__))
#define __WI_FOR_imp86(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp85(fn, __VA_ARGS__))
#define __WI_FOR_imp87(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp86(fn, __VA_ARGS__))
#define __WI_FOR_imp88(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp87(fn, __VA_ARGS__))
#define __WI_FOR_imp89(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp88(fn, __VA_ARGS__))
#define __WI_FOR_imp90(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp89(fn, __VA_ARGS__))
#define __WI_FOR_imp91(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp90(fn, __VA_ARGS__))
#define __WI_FOR_imp92(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp91(fn, __VA_ARGS__))
#define __WI_FOR_imp93(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp92(fn, __VA_ARGS__))
#define __WI_FOR_imp94(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp93(fn, __VA_ARGS__))
#define __WI_FOR_imp95(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp94(fn, __VA_ARGS__))
#define __WI_FOR_imp96(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp95(fn, __VA_ARGS__))
#define __WI_FOR_imp97(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp96(fn, __VA_ARGS__))
#define __WI_FOR_imp98(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp97(fn, __VA_ARGS__))
#define __WI_FOR_imp99(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp98(fn, __VA_ARGS__))
#define __WI_FOR_imp(n, fnAndArgs) WI_PASTE(__WI_FOR_imp, n) fnAndArgs
/// @endcond
//! Iterates through each of the given arguments invoking the specified macro against each one.
#define WI_FOREACH(fn, ...) __WI_FOR_imp(WI_ARGS_COUNT(__VA_ARGS__), (fn, ##__VA_ARGS__))
//! Dispatches a single macro name to separate macros based on the number of arguments passed to it.
#define WI_MACRO_DISPATCH(name, ...) WI_PASTE(WI_PASTE(name, WI_ARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
//! @} // Macro composition helpers
#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL)
#define WI_ODR_PRAGMA(NAME, TOKEN)
#define WI_NOEXCEPT
#else
#pragma warning(push)
#pragma warning(disable : 4714) // __forceinline not honored
// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage
#include "wistd_type_traits.h"
//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
#ifdef WIL_KERNEL_MODE
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
#else
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0")
#endif
#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(WIL_SUPPRESS_EXCEPTIONS)
/** This define is automatically set when exceptions are enabled within wil.
It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in
_CPPUNWIND or __EXCEPTIONS flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil
header. All exception-based WIL methods and classes are included behind:
~~~~
#ifdef WIL_ENABLE_EXCEPTIONS
// code
#endif
~~~~
This enables exception-free code to directly include WIL headers without worrying about exception-based
routines suddenly becoming available. */
#define WIL_ENABLE_EXCEPTIONS
#endif
/// @cond
#if defined(WIL_EXCEPTION_MODE)
static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode");
#elif !defined(WIL_LOCK_EXCEPTION_MODE)
#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0")
#elif defined(WIL_ENABLE_EXCEPTIONS)
#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1")
#else
#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions
#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2")
#endif
/// @endcond
#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS)
#error Must enable exceptions when WIL_EXCEPTION_MODE == 1
#endif
#ifdef WIL_DOXYGEN
/** This define is used to control whether or not WIL assumes safe access to the STL.
This define can be set manually (1 to enable, 0 to disable), otherwise heuristics will be applied in an attempt to
deduce whether or not the STL is available and can be safely used.
*/
#define WIL_USE_STL 1
#elif !defined(WIL_USE_STL)
#if !defined(WIL_ENABLE_EXCEPTIONS) || !defined(__has_include)
// Assume it's not safe to use the STL when:
// * Exceptions are not enabled, OR
// * We can't check for header presence
#define WIL_USE_STL 0
#else
// Check for several STL headers that have been around since the dawn of time
#if __has_include(<algorithm>) && __has_include(<exception>) && __has_include(<iterator>) && __has_include(<new>) && \
__has_include(<string>) && __has_include(<utility>) && __has_include(<vector>)
#define WIL_USE_STL 1
#else
#define WIL_USE_STL 0
#endif
#endif
#endif
/// @cond
#ifndef WIL_ITERATOR_DEBUG_LEVEL
// NOTE: See the definition of 'RESULT_DEBUG' for commentary on the use of 'WIL_KERNEL_MODE' below
#if (DBG || defined(DEBUG) || defined(_DEBUG)) && (defined(WIL_KERNEL_MODE) || !defined(NDEBUG))
#define WIL_ITERATOR_DEBUG_LEVEL 2
#else
#define WIL_ITERATOR_DEBUG_LEVEL 0
#endif
#endif
#if (WIL_ITERATOR_DEBUG_LEVEL < 0) || (WIL_ITERATOR_DEBUG_LEVEL > 2)
#error Invalid value for 'WIL_ITERATOR_DEBUG_LEVEL'; valid values are 0-2
#endif
// To allow code with mis-matching iterator debug levels to link together without fear of ODR issues, we place iterators whose
// definitions differ based on the definition of WIL_ITERATOR_DEBUG_LEVEL in different namespaces
#if WIL_ITERATOR_DEBUG_LEVEL > 0
#define __WI_ITR_NAMESPACE WI_PASTE(itr, WIL_ITERATOR_DEBUG_LEVEL)
#define __WI_ITR_NAMESPACE_BEGIN \
inline namespace __WI_ITR_NAMESPACE \
{
#define __WI_ITR_NAMESPACE_END }
#else
#define __WI_ITR_NAMESPACE
#define __WI_ITR_NAMESPACE_BEGIN
#define __WI_ITR_NAMESPACE_END
#endif
/// @endcond
// block for documentation only
#if defined(WIL_DOXYGEN)
/** This define can be explicitly set to disable exception usage within wil.
Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking
at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based
classes and methods from WIL, define this macro ahead of including the first WIL header. */
#define WIL_SUPPRESS_EXCEPTIONS
/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS.
Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the
need to do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid
ODR violations when linking libraries together with different exception handling semantics. */
#define WIL_LOCK_EXCEPTION_MODE
/** This define explicit sets the exception mode for the process to control optimizations.
Three exception modes are available:
0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that use
WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR
violations when linking libraries together with different exception handling semantics.
1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions
enabled.
2) This locks the binary to libraries built without exceptions. */
#define WIL_EXCEPTION_MODE
/**This define controls the degree of runtime checking for various iterator types defined by WIL.
This option roughly follows the behavior of the MSVC STL's `_ITERATOR_DEBUG_LEVEL` define, with similar available values. The
primary difference (besides being two disjoint values) is that `WIL_ITERATOR_DEBUG_LEVEL` will raise a failfast exception when a
check fails as opposed to the invalid parameter handler that the STL invokes. There are three definitions allowed:
0) This will disable all additional runtime checks for the various iterator types. This is the default when building as 'Release'
1) This enables checks only for unsafe iterator use. This includes things like attempting to increment an iterator past the end,
dereference an end iterator, dereference invalidated iterators, etc.
2) This enables all checks enabled by level 1 plus some additional checks to try and catch invalid iterator use. The specific
checks enabled by this level will vary between iterator types. This is the default when building as 'Debug'
*/
#define WIL_ITERATOR_DEBUG_LEVEL 0
#endif
/// @cond
// Until we'll have C++17 enabled in our code base, we're falling back to SAL
#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE
#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t<wistd::is_class<ptrType>::value, void*> = nullptr
#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void*> = nullptr
// Uses the __has_include macro, if available. Otherwise uses a user-provided fallback. E.g. the fallback could always
// default to true or false, or it could do something like a C++ standard version check
#ifdef __has_include
#define WI_HAS_INCLUDE(header, fallback) __has_include(header)
#else
#define WI_HAS_INCLUDE(header, fallback) (fallback)
#endif
/// @endcond
//! @defgroup bitwise Bitwise Inspection and Manipulation
//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations.
//! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist
//! for two primary purposes:
//!
//! 1. To improve the readability of bitwise comparisons and manipulation.
//!
//! The macro names are the more concise, readable form of what's being done and do not require that any flags
//! or variables be specified multiple times for the comparisons.
//!
//! 2. To reduce the error rate associated with bitwise operations.
//!
//! The readability improvements naturally lend themselves to this by cutting down the number of concepts.
//! Using `WI_IsFlagSet(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison
//! operator and repetition in the flag value.
//!
//! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag
//! operations so that compile-time errors are generated for bitwise operations which are likely incorrect,
//! such as: `WI_IsFlagSet(var, MyEnum::None)` or `WI_IsFlagSet(var, MyEnum::ValidMask)`.
//!
//! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These
//! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers
//! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants.
//!
//! Common example usage (manipulation of flag variables):
//! ~~~~
//! WI_SetFlag(m_flags, MyFlags::Foo); // Set a single flag in the given variable
//! WI_SetAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags
//! WI_ClearFlagIf(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool
//! WI_ClearAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable
//! WI_ToggleFlag(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag
//! WI_UpdateFlag(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based
//! // upon a bool value
//! WI_UpdateFlagsInMask(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values
//! // from newFlagValues
//! ~~~~
//! Common example usage (inspection of flag variables):
//! ~~~~
//! if (WI_IsFlagSet(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable?
//! if (WI_IsAnyFlagSet(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set?
//! if (WI_AreAllFlagsClear(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear?
//! if (WI_IsSingleFlagSet(m_flags)) // Is *exactly* one flag set in the given variable?
//! ~~~~
//! @{
//! Returns the unsigned type of the same width and numeric value as the given enum
#define WI_EnumValue(val) static_cast<::wil::integral_from_enum<decltype(val)>>(val)
//! Validates that exactly ONE bit is set in compile-time constant `flag`
#define WI_StaticAssertSingleBitSet(flag) \
static_cast<decltype(flag)>(::wil::details::verify_single_flag_helper<static_cast<unsigned long long>(WI_EnumValue(flag))>::value)
//! @name Bitwise manipulation macros
//! @{
//! Set zero or more bitflags specified by `flags` in the variable `var`.
#define WI_SetAllFlags(var, flags) ((var) |= (flags))
//! Set a single compile-time constant `flag` in the variable `var`.
#define WI_SetFlag(var, flag) WI_SetAllFlags(var, WI_StaticAssertSingleBitSet(flag))
//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true.
#define WI_SetFlagIf(var, flag, condition) \
do \
{ \
if (wil::verify_bool(condition)) \
{ \
WI_SetFlag(var, flag); \
} \
} while ((void)0, 0)
//! Clear zero or more bitflags specified by `flags` from the variable `var`.
#define WI_ClearAllFlags(var, flags) ((var) &= ~(flags))
//! Clear a single compile-time constant `flag` from the variable `var`.
#define WI_ClearFlag(var, flag) WI_ClearAllFlags(var, WI_StaticAssertSingleBitSet(flag))
//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true.
#define WI_ClearFlagIf(var, flag, condition) \
do \
{ \
if (wil::verify_bool(condition)) \
{ \
WI_ClearFlag(var, flag); \
} \
} while ((void)0, 0)
//! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet`
//! is false.
#define WI_UpdateFlag(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SetFlag(var, flag) : WI_ClearFlag(var, flag))
//! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`.
#define WI_UpdateFlagsInMask(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags)
//! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`.
#define WI_ToggleAllFlags(var, flags) ((var) ^= (flags))
//! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`.
#define WI_ToggleFlag(var, flag) WI_ToggleAllFlags(var, WI_StaticAssertSingleBitSet(flag))
//! @} // bitwise manipulation macros
//! @name Bitwise inspection macros
//! @{
//! Evaluates as true if every bitflag specified in `flags` is set within `val`.
#define WI_AreAllFlagsSet(val, flags) wil::details::AreAllFlagsSetHelper(val, flags)
//! Evaluates as true if one or more bitflags specified in `flags` are set within `val`.
#define WI_IsAnyFlagSet(val, flags) \
(static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast<decltype((val) & (flags))>(0))
//! Evaluates as true if a single compile-time constant `flag` is set within `val`.
#define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag))
//! Evaluates as true if every bitflag specified in `flags` is clear within `val`.
#define WI_AreAllFlagsClear(val, flags) \
(static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast<decltype((val) & (flags))>(0))
//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`.
#define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags))
//! Evaluates as true if a single compile-time constant `flag` is clear within `val`.
#define WI_IsFlagClear(val, flag) WI_AreAllFlagsClear(val, WI_StaticAssertSingleBitSet(flag))
//! Evaluates as true if exactly one bit (any bit) is set within `val`.
#define WI_IsSingleFlagSet(val) wil::details::IsSingleFlagSetHelper(val)
//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`.
#define WI_IsSingleFlagSetInMask(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask))
//! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`.
#define WI_IsClearOrSingleFlagSet(val) wil::details::IsClearOrSingleFlagSetHelper(val)
//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask`
//! set within `val`.
#define WI_IsClearOrSingleFlagSetInMask(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask))
//! @} // bitwise inspection macros
//! @} // group bitwise
#if defined(WIL_DOXYGEN)
/** This macro provides a C++ header with a guaranteed initialization function.
Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw
the object away if it's unreferenced (which throws away the side-effects that the initialization function
was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the
provided function to elide that optimization.
//!
This functionality is primarily provided as a building block for header-based libraries (such as WIL)
to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models
of initialization should be used whenever they are available.
~~~~
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
WI_HEADER_INITIALIZATION_FUNCTION(InitializeDesktopFamilyApis, []
{
g_pfnGetModuleName = GetCurrentModuleName;
g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout;
return 1;
});
#endif
~~~~
The above example is used within WIL to decide whether or not the library containing WIL is allowed to use
desktop APIs. Building this functionality as `#IFDEF`s within functions would create ODR violations, whereas
doing it with global function pointers and header initialization allows a runtime determination. */
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn)
#elif defined(_M_IX86)
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
extern "C" \
{ \
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
} \
__pragma(comment(linker, "/INCLUDE:_g_header_init_" #name))
#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
extern "C" \
{ \
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
} \
__pragma(comment(linker, "/INCLUDE:g_header_init_" #name))
#else
#error linker pragma must include g_header_init variation
#endif
// Keep the misspelled name for backward compatibility.
#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) WI_HEADER_INITIALIZATION_FUNCTION(name, fn)
/** All Windows Implementation Library classes and functions are located within the "wil" namespace.
The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference
the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using
statement for wil to avoid introducing potential name collisions between wil and other namespaces. */
namespace wil
{
/// @cond
namespace details
{
template <typename T>
class pointer_range
{
public:
pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_)
{
}
WI_NODISCARD T begin() const
{
return m_begin;
}
WI_NODISCARD T end() const
{
return m_end;
}
private:
T m_begin;
T m_end;
};
} // namespace details
/// @endcond
/** Enables using range-based for between a begin and end object pointer.
~~~~
for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { }
~~~~ */
template <typename T>
details::pointer_range<T> make_range(T begin, T end)
{
return details::pointer_range<T>(begin, end);
}
/** Enables using range-based for on a range when given the base pointer and the number of objects in the range.
~~~~
for (auto& obj : make_range(objPointer, objCount)) { }
~~~~ */
template <typename T>
details::pointer_range<T> make_range(T begin, size_t count)
{
return details::pointer_range<T>(begin, begin + count);
}
//! @defgroup outparam Output Parameters
//! Improve the conciseness of assigning values to optional output parameters.
//! @{
/** Assign the given value to an optional output parameter.
Makes code more concise by removing trivial `if (outParam)` blocks. */
template <typename T>
inline void assign_to_opt_param(_Out_opt_ T* outParam, T val)
{
if (outParam != nullptr)
{
*outParam = val;
}
}
/** Assign NULL to an optional output pointer parameter.
Makes code more concise by removing trivial `if (outParam)` blocks. */
template <typename T>
inline void assign_null_to_opt_param(_Out_opt_ T* outParam)
{
if (outParam != nullptr)
{
*outParam = nullptr;
}
}
//! @} // end output parameter helpers
/** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation.
Example usage:
~~~~
template <unsigned int... Rest>
struct FeatureRequiredBy
{
static const bool enabled = wil::variadic_logical_or<WilFeature<Rest>::enabled...>::value;
};
~~~~ */
template <bool...>
struct variadic_logical_or;
/// @cond
template <>
struct variadic_logical_or<> : wistd::false_type
{
};
template <bool... Rest>
struct variadic_logical_or<true, Rest...> : wistd::true_type
{
};
template <bool... Rest>
struct variadic_logical_or<false, Rest...> : variadic_logical_or<Rest...>::type
{
};
/// @endcond
/// @cond
namespace details
{
template <unsigned long long flag>
struct verify_single_flag_helper
{
static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found");
static const unsigned long long value = flag;
};
} // namespace details
/// @endcond
//! @defgroup typesafety Type Validation
//! Helpers to validate variable types to prevent accidental, but allowed type conversions.
//! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types
//! accepted prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional
//! layer of type safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in
//! the error handling helper macros to validate the types given to various macro parameters.
//! @{
/** Verify that `val` can be evaluated as a logical bool.
Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL,
boolean, BOOLEAN, and classes with an explicit bool cast.
@param val The logical bool expression
@return A C++ bool representing the evaluation of `val`. */
template <typename T, __R_ENABLE_IF_IS_CLASS(T)>
_Post_satisfies_(return == static_cast<bool>(val)) inline constexpr bool verify_bool(const T& val) WI_NOEXCEPT
{
return static_cast<bool>(val);
}
template <typename T, __R_ENABLE_IF_IS_NOT_CLASS(T)>
inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT
{
static_assert(!wistd::is_same<T, T>::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
return false;
}
template <>
_Post_satisfies_(return == val) inline constexpr bool verify_bool<bool>(bool val) WI_NOEXCEPT
{
return val;
}
template <>
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<int>(int val) WI_NOEXCEPT
{
return (val != 0);
}
template <>
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<unsigned char>(unsigned char val) WI_NOEXCEPT
{
return (val != 0);
}
/** Verify that `val` is a Win32 BOOL value.
Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will
accept any `int` value as long as that is the underlying typedef behind `BOOL`.
@param val The Win32 BOOL returning expression
@return A Win32 BOOL representing the evaluation of `val`. */
template <typename T>
_Post_satisfies_(return == val) inline constexpr int verify_BOOL(T val) WI_NOEXCEPT
{
// Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL;
static_assert((wistd::is_same<T, int>::value), "Wrong Type: BOOL expected");
return val;
}
/** Verify that `hr` is an HRESULT value.
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
underlying typedef behind HRESULT.
Note that occasionally you might run into an HRESULT which is directly defined with a `#define`, such as:
~~~~
#define UIA_E_NOTSUPPORTED 0x80040204
~~~~
Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
their definition to match the manner in which `HRESULT` constants are defined in winerror.h:
~~~~
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
~~~~
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
to use this value in a macro that utilizes `verify_hresult`, for example:
~~~~
RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
~~~~
@param hr The HRESULT returning expression
@return An HRESULT representing the evaluation of `val`. */
template <typename T>
_Post_satisfies_(return == hr) inline constexpr long verify_hresult(T hr) WI_NOEXCEPT
{
// Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
static_assert(wistd::is_same<T, long>::value, "Wrong Type: HRESULT expected");
return hr;
}
/** Verify that `status` is an NTSTATUS value.
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the
underlying typedef behind NTSTATUS.
//!
Note that occasionally you might run into an NTSTATUS which is directly defined with a `#define`, such as:
@code
#define STATUS_NOT_SUPPORTED 0x1
@endcode
Though this looks like an `NTSTATUS`, this is actually an `unsigned long` (the hex specification forces this). When
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
their definition to match the manner in which `NTSTATUS` constants are defined in ntstatus.h:
@code
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
@endcode
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
to use this value in a macro that utilizes `verify_ntstatus`, for example:
@code
NT_RETURN_IF_FALSE(static_cast<NTSTATUS>(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0));
@endcode
@param status The NTSTATUS returning expression
@return An NTSTATUS representing the evaluation of `val`. */
template <typename T>
_Post_satisfies_(return == status) inline long verify_ntstatus(T status) WI_NOEXCEPT
{
// Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long NTSTATUS
static_assert(wistd::is_same<T, long>::value, "Wrong Type: NTSTATUS expected");
return status;
}
/** Verify that `error` is a Win32 error code.
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type
commonly used when manipulating Win32 error codes.
@param error The Win32 error code returning expression
@return An Win32 error code representing the evaluation of `error`. */
template <typename T>
_Post_satisfies_(return == error) inline T verify_win32(T error) WI_NOEXCEPT
{
// Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned
// long). This accept both types.
static_assert(
wistd::is_same<T, long>::value || wistd::is_same<T, unsigned long>::value,
"Wrong Type: Win32 error code (long / unsigned long) expected");
return error;
}
/// @} // end type validation routines
/// @cond
// Implementation details for macros and helper functions... do not use directly.
namespace details
{
// Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value
#define __WI_MAKE_UNSIGNED(val) \
(__pragma(warning(push)) __pragma(warning(disable : 4310 4309))( \
sizeof(val) == 1 ? static_cast<unsigned char>(val) \
: sizeof(val) == 2 ? static_cast<unsigned short>(val) \
: sizeof(val) == 4 ? static_cast<unsigned long>(val) \
: static_cast<unsigned long long>(val)) __pragma(warning(pop)))
#define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1)))
#define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val))
template <typename TVal, typename TFlags>
__forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags)
{
return ((val & flags) == static_cast<decltype(val & flags)>(flags));
}
template <typename TVal>
__forceinline constexpr bool IsSingleFlagSetHelper(TVal val)
{
return __WI_IS_SINGLE_FLAG_SET(val);
}
template <typename TVal>
__forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val)
{
return ((val == static_cast<wistd::remove_reference_t<TVal>>(0)) || IsSingleFlagSetHelper(val));
}
template <typename TVal, typename TMask, typename TFlags>
__forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags)
{
val = static_cast<wistd::remove_reference_t<TVal>>((val & ~mask) | (flags & mask));
}
template <long>
struct variable_size;
template <>
struct variable_size<1>
{
using type = unsigned char;
};
template <>
struct variable_size<2>
{
using type = unsigned short;
};
template <>
struct variable_size<4>
{
using type = unsigned long;
};
template <>
struct variable_size<8>
{
using type = unsigned long long;
};
template <typename T>
struct variable_size_mapping
{
using type = typename variable_size<sizeof(T)>::type;
};
} // namespace details
/// @endcond
/** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type.
This allows code to generically convert any enum class to it's corresponding underlying type. */
template <typename T>
using integral_from_enum = typename details::variable_size_mapping<T>::type;
//! Declares a name that intentionally hides a name from an outer scope.
//! Use this to prevent accidental use of a parameter or lambda captured variable.
using hide_name = void(struct hidden_name);
} // namespace wil
#pragma warning(pop)
#endif // __cplusplus
#endif // __WIL_COMMON_INCLUDED

935
d3d11.x/wil/coroutine.h Normal file
View File

@@ -0,0 +1,935 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Types and helpers for using C++ coroutines.
#ifndef __WIL_COROUTINE_INCLUDED
#define __WIL_COROUTINE_INCLUDED
/*
* A wil::task<T> / com_task<T> is a coroutine with the following characteristics:
*
* - T must be a copyable object, movable object, reference, or void.
* - The coroutine may be awaited at most once. The second await will crash.
* - The coroutine may be abandoned (allowed to destruct without co_await),
* in which case unobserved exceptions are fatal.
* - By default, wil::task resumes on an arbitrary thread.
* - By default, wil::com_task resumes in the same COM apartment.
* - task.resume_any_thread() allows resumption on any thread.
* - task.resume_same_apartment() forces resumption in the same COM apartment.
*
* The wil::task and wil::com_task are intended to supplement PPL and C++/WinRT,
* not to replace them. It provides coroutine implementations for scenarios that PPL
* and C++/WinRT do not support, but it does not support everything that PPL and
* C++/WinRT do.
*
* The implementation is optimized on the assumption that the coroutine is
* awaited only once, and that the coroutine is discarded after completion.
* To ensure proper usage, the task object is move-only, and
* co_await takes ownership of the task. See further discussion below.
*
* Comparison with PPL and C++/WinRT:
*
* | | PPL | C++/WinRT | wil::*task |
* |-----------------------------------------------------|-----------|-----------|---------------|
* | T can be non-constructible | No | Yes | Yes |
* | T can be void | Yes | Yes | Yes |
* | T can be reference | No | No | Yes |
* | T can be WinRT object | Yes | Yes | Yes |
* | T can be non-WinRT object | Yes | No | Yes |
* | T can be move-only | No | No | Yes |
* | Coroutine can be cancelled | Yes | Yes | No |
* | Coroutine can throw arbitrary exceptions | Yes | No | Yes |
* | Can co_await more than once | Yes | No | No |
* | Can have multiple clients waiting for completion | Yes | No | No |
* | co_await resumes in same COM context | Sometimes | Yes | You choose [1]|
* | Can force co_await to resume in same context | Yes | N/A | Yes [1] |
* | Can force co_await to resume in any thread | Yes | No | Yes |
* | Can change coroutine's resumption model | No | No | Yes |
* | Can wait synchronously | Yes | Yes | Yes [2] |
* | Can be consumed by non-C++ languages | No | Yes | No |
* | Implementation is small and efficient | No | Yes | Yes |
* | Can abandon coroutine (fail to co_await) | Yes | Yes | Yes |
* | Exception in abandoned coroutine | Crash | Ignored | Crash |
* | Coroutine starts automatically | Yes | Yes | Yes |
* | Coroutine starts synchronously | No | Yes | Yes |
* | Integrates with C++/WinRT coroutine callouts | No | Yes | No |
*
* [1] Resumption in the same COM apartment requires that you include COM headers.
* [2] Synchronous waiting requires that you include <synchapi.h> (usually via <windows.h>).
*
* You can include the COM headers and/or synchapi.h headers, and then
* re-include this header file to activate the features dependent upon
* those headers.
*
* Examples:
*
* Implement a coroutine that returns a move-only non-WinRT type
* and which resumes on an arbitrary thread.
*
* wil::task<wil::unique_cotaskmem_string> GetNameAsync()
* {
* co_await resume_background(); // do work on BG thread
* wil::unique_cotaskmem_string name;
* THROW_IF_FAILED(GetNameSlow(&name));
* co_return name; // awaiter will resume on arbitrary thread
* }
*
* Consumers:
*
* winrt::IAsyncAction UpdateNameAsync()
* {
* // wil::task resumes on an arbitrary thread.
* auto name = co_await GetNameAsync();
* // could be on any thread now
* co_await SendNameAsync(name.get());
* }
*
* winrt::IAsyncAction UpdateNameAsync()
* {
* // override default behavior of wil::task and
* // force it to resume in the same COM apartment.
* auto name = co_await GetNameAsync().resume_same_apartment();
* // so we are still on the UI thread
* NameElement().Text(winrt::hstring(name.get()));
* }
*
* Conversely, a coroutine that returns a
* wil::com_task<T> defaults to resuming in the same
* COM apartment, but you can allow it to resume on any thread
* by doing co_await GetNameAsync().resume_any_thread().
*
* There is no harm in doing resume_same_apartment() / resume_any_thread() for a
* task that already defaults to resuming in that manner. In fact, awaiting the
* task directly is just a shorthand for awaiting the corresponding
* resume_whatever() method.
*
* Alternatively, you can just convert between wil::task<T> and wil::com_task<T>
* to change the default resumption context.
*
* co_await wil::com_task(GetNameAsync()); // now defaults to resume_same_apartment();
*
* You can store the task in a variable, but since it is a move-only
* object, you will have to use std::move in order to transfer ownership out of
* an lvalue.
*
* winrt::IAsyncAction SomethingAsync()
* {
* wil::com_task<int> task;
* switch (source)
* {
* // Some of these might return wil::task<int>,
* // but assigning to a wil::com_task<int> will make
* // the task resume in the same COM apartment.
* case widget: task = GetValueFromWidgetAsync(); break;
* case gadget: task = GetValueFromGadgetAsync(); break;
* case doodad: task = GetValueFromDoodadAsync(); break;
* default: FAIL_FAST(); // unknown source
* }
* auto value = co_await std::move(task); // **** need std::move
* DoSomethingWith(value);
* }
*
* You can wait synchronously by calling get(). The usual caveats
* about synchronous waits on STA threads apply.
*
* auto value = GetValueFromWidgetAsync().get();
*
* auto task = GetValueFromWidgetAsync();
* auto value = std::move(task).get(); // **** need std::move
*/
// Detect which version of the coroutine standard we have.
/// @cond
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
#include <experimental/coroutine>
#define __WI_COROUTINE_NAMESPACE ::std::experimental
#elif defined(__cpp_impl_coroutine)
#include <coroutine>
#define __WI_COROUTINE_NAMESPACE ::std
#else
#error You must compile with C++20 coroutine support to use coroutine.h.
#endif
/// @endcond
#include <atomic>
#include <exception>
#include <utility>
#include <wil/wistd_memory.h>
#include <wil/wistd_type_traits.h>
#include <wil/result_macros.h>
namespace wil
{
// There are three general categories of T that you can
// use with a task. We give them these names:
//
// T = void ("void category")
// T = some kind of reference ("reference category")
// T = non-void non-reference ("object category")
//
// Take care that the implementation supports all three categories.
//
// There is a sub-category of object category for move-only types.
// We designed our task to be co_awaitable only once, so that
// it can contain a move-only type. Any transfer of T as an
// object category must be done as an rvalue reference.
template <typename T>
struct task;
template <typename T>
struct com_task;
} // namespace wil
/// @cond
namespace wil::details::coro
{
// task and com_task are convertible to each other. However, not
// all consumers of this header have COM enabled. Support for saving
// COM thread-local error information and restoring it on the resuming
// thread is enabled using these function pointers. If COM is not
// available then they are null and do not get called. If COM is
// enabled then they are filled in with valid pointers and get used.
__declspec(selectany) void*(__stdcall* g_pfnCaptureRestrictedErrorInformation)() WI_PFN_NOEXCEPT = nullptr;
__declspec(selectany) void(__stdcall* g_pfnRestoreRestrictedErrorInformation)(void* restricted_error) WI_PFN_NOEXCEPT = nullptr;
__declspec(selectany) void(__stdcall* g_pfnDestroyRestrictedErrorInformation)(void* restricted_error) WI_PFN_NOEXCEPT = nullptr;
template <typename T>
struct task_promise;
// Unions may not contain references, C++/CX types, or void.
// To work around that, we put everything inside a result_wrapper
// struct, and put the struct in the union. For void,
// we create a special empty structure.
//
// get_value returns rvalue reference to T for object
// category, or just T itself for void and reference
// category.
//
// We take advantage of the reference collapsing rules
// so that T&& = T if T is reference category.
template <typename T>
struct result_wrapper
{
T value;
T get_value()
{
return wistd::forward<T>(value);
}
};
template <>
struct result_wrapper<void>
{
void get_value()
{
}
};
// The result_holder is basically a
// std::variant<std::monotype, T, std::exception_ptr>
// but with these extra quirks:
// * The only valid transition is monotype -> something-else.
// Consequently, it does not have valueless_by_exception.
template <typename T>
struct result_holder
{
// The content of the result_holder
// depends on the result_status:
//
// empty: No active member.
// value: Active member is wrap.
// error: Active member is error.
enum class result_status
{
empty,
value,
error
};
result_status status{result_status::empty};
union variant
{
variant()
{
}
~variant()
{
}
result_wrapper<T> wrap;
std::exception_ptr error;
} result;
// The restricted error information is lit up when COM headers are
// included. If COM is not available then this will remain null.
// This error information is thread-local so we must save it on suspend
// and restore it on resume so that it propagates to the correct
// thread. It will then be available if the exception proves fatal.
//
// This object is non-copyable so we do not need to worry about
// supporting AddRef on the restricted error information.
void* restricted_error{nullptr};
// emplace_value will be called with
//
// * no parameters (void category)
// * The reference type T (reference category)
// * Some kind of reference to T (object category)
//
// Set the status after constructing the object.
// That way, if object construction throws an exception,
// the holder remains empty.
template <typename... Args>
void emplace_value(Args&&... args)
{
WI_ASSERT(status == result_status::empty);
new (wistd::addressof(result.wrap)) result_wrapper<T>{wistd::forward<Args>(args)...};
status = result_status::value;
}
void unhandled_exception() noexcept
{
if (g_pfnCaptureRestrictedErrorInformation)
{
WI_ASSERT(restricted_error == nullptr);
restricted_error = g_pfnCaptureRestrictedErrorInformation();
}
WI_ASSERT(status == result_status::empty);
new (wistd::addressof(result.error)) std::exception_ptr(std::current_exception());
status = result_status::error;
}
T get_value()
{
if (status == result_status::value)
{
return result.wrap.get_value();
}
WI_ASSERT(status == result_status::error);
if (restricted_error && g_pfnRestoreRestrictedErrorInformation)
{
g_pfnRestoreRestrictedErrorInformation(restricted_error);
}
std::rethrow_exception(wistd::exchange(result.error, {}));
}
result_holder() = default;
result_holder(result_holder const&) = delete;
void operator=(result_holder const&) = delete;
~result_holder() noexcept(false)
{
if (restricted_error && g_pfnDestroyRestrictedErrorInformation)
{
g_pfnDestroyRestrictedErrorInformation(restricted_error);
restricted_error = nullptr;
}
switch (status)
{
case result_status::value:
result.wrap.~result_wrapper();
break;
case result_status::error:
// Rethrow unobserved exception. Delete this line to
// discard unobserved exceptions.
if (result.error)
std::rethrow_exception(result.error);
result.error.~exception_ptr();
}
}
};
// Most of the work is done in the promise_base,
// It is a CRTP-like base class for task_promise<void> and
// task_promise<non-void> because the language forbids
// a single promise from containing both return_value and
// return_void methods (even if one of them is deleted by SFINAE).
template <typename T>
struct promise_base
{
// The coroutine state remains alive as long as the coroutine is
// still running (hasn't reached final_suspend) or the associated
// task has not yet abandoned the coroutine (either finished awaiting
// or destructed without awaiting).
//
// This saves an allocation, but does mean that the local
// frame of the coroutine will remain allocated (with the
// coroutine's imbound parameters still live) until all
// references are destroyed. To force the promise_base to be
// destroyed after co_await, we make the promise_base a
// move-only object and require co_await to be given an rvalue reference.
// Special values for m_waiting.
static void* running_ptr()
{
return nullptr;
}
static void* completed_ptr()
{
return reinterpret_cast<void*>(1);
}
static void* abandoned_ptr()
{
return reinterpret_cast<void*>(2);
}
// The awaiting coroutine is resumed by calling the
// m_resumer with the m_waiting. If the resumer is null,
// then the m_waiting is assumed to be the address of a
// coroutine_handle<>, which is resumed synchronously.
// Externalizing the resumer allows unused awaiters to be
// removed by the linker and removes a hard dependency on COM.
// Using nullptr to represent the default resumer avoids a
// CFG check.
void(__stdcall* m_resumer)(void*);
std::atomic<void*> m_waiting{running_ptr()};
result_holder<T> m_holder;
// Make it easier to access our CRTP derived class.
using Promise = task_promise<T>;
auto as_promise() noexcept
{
return static_cast<Promise*>(this);
}
// Make it easier to access the coroutine handle.
auto as_handle() noexcept
{
return __WI_COROUTINE_NAMESPACE::coroutine_handle<Promise>::from_promise(*as_promise());
}
auto get_return_object() noexcept
{
// let the compiler construct the task / com_task from the promise.
return as_promise();
}
void destroy()
{
as_handle().destroy();
}
// The client lost interest in the coroutine, either because they are discarding
// the result without awaiting (risky!), or because they have finished awaiting.
// Discarding the result without awaiting is risky because any exception in the coroutine
// will be unobserved and result in a crash. If you want to disallow it, then
// raise an exception if waiting == running_ptr.
void abandon()
{
auto waiting = m_waiting.exchange(abandoned_ptr(), std::memory_order_acq_rel);
if (waiting != running_ptr())
destroy();
}
__WI_COROUTINE_NAMESPACE::suspend_never initial_suspend() noexcept
{
return {};
}
template <typename... Args>
void emplace_value(Args&&... args)
{
m_holder.emplace_value(wistd::forward<Args>(args)...);
}
void unhandled_exception() noexcept
{
m_holder.unhandled_exception();
}
void resume_waiting_coroutine(void* waiting) const
{
if (m_resumer)
{
m_resumer(waiting);
}
else
{
__WI_COROUTINE_NAMESPACE::coroutine_handle<>::from_address(waiting).resume();
}
}
auto final_suspend() noexcept
{
struct awaiter : __WI_COROUTINE_NAMESPACE::suspend_always
{
promise_base& self;
void await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<>) const noexcept
{
// Need acquire so we can read from m_resumer.
// Need release so that the results are published in the case that nobody
// is awaiting right now, so that the eventual awaiter (possibly on another thread)
// can read the results.
auto waiting = self.m_waiting.exchange(completed_ptr(), std::memory_order_acq_rel);
if (waiting == abandoned_ptr())
{
self.destroy();
}
else if (waiting != running_ptr())
{
WI_ASSERT(waiting != completed_ptr());
self.resume_waiting_coroutine(waiting);
}
};
};
return awaiter{{}, *this};
}
// The remaining methods are used by the awaiters.
bool client_await_ready()
{
// Need acquire in case the coroutine has already completed,
// so we can read the results. This matches the release in
// the final_suspend's await_suspend.
auto waiting = m_waiting.load(std::memory_order_acquire);
WI_ASSERT((waiting == running_ptr()) || (waiting == completed_ptr()));
return waiting != running_ptr();
}
auto client_await_suspend(void* waiting, void(__stdcall* resumer)(void*))
{
// "waiting" needs to be a pointer to an object. We reserve the first 16
// pseudo-pointers as sentinels.
WI_ASSERT(reinterpret_cast<uintptr_t>(waiting) > 16);
m_resumer = resumer;
// Acquire to ensure that we can read the results of the return value, if the coroutine is completed.
// Release to ensure that our resumption state is published, if the coroutine is not completed.
auto previous = m_waiting.exchange(waiting, std::memory_order_acq_rel);
// Suspend if the coroutine is still running.
// Otherwise, the coroutine is completed: Nobody will resume us, so we will have to resume ourselves.
WI_ASSERT((previous == running_ptr()) || (previous == completed_ptr()));
return previous == running_ptr();
}
T client_await_resume()
{
return m_holder.get_value();
}
};
template <typename T>
struct task_promise : promise_base<T>
{
template <typename U>
void return_value(U&& value)
{
this->emplace_value(wistd::forward<U>(value));
}
template <typename Dummy = void>
wistd::enable_if_t<!wistd::is_reference_v<T>, Dummy> return_value(T const& value)
{
this->emplace_value(value);
}
};
template <>
struct task_promise<void> : promise_base<void>
{
void return_void()
{
this->emplace_value();
}
};
template <typename T>
struct promise_deleter
{
void operator()(promise_base<T>* promise) const noexcept
{
promise->abandon();
}
};
template <typename T>
using promise_ptr = wistd::unique_ptr<promise_base<T>, promise_deleter<T>>;
template <typename T>
struct agile_awaiter
{
agile_awaiter(promise_ptr<T>&& initial) : promise(wistd::move(initial))
{
}
promise_ptr<T> promise;
bool await_ready()
{
return promise->client_await_ready();
}
auto await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle)
{
// Use the default resumer.
return promise->client_await_suspend(handle.address(), nullptr);
}
T await_resume()
{
return promise->client_await_resume();
}
};
template <typename T>
struct task_base
{
auto resume_any_thread() && noexcept
{
return agile_awaiter<T>{wistd::move(promise)};
}
// You must #include <ole2.h> before <wil/coroutine.h> to enable apartment-aware awaiting.
auto resume_same_apartment() && noexcept;
// Compiler error message metaprogramming: Tell people that they
// need to use std::move() if they try to co_await an lvalue.
struct cannot_await_lvalue_use_std_move
{
void await_ready()
{
}
};
cannot_await_lvalue_use_std_move operator co_await() & = delete;
// You must #include <synchapi.h> (usually via <windows.h>) to enable synchronous waiting.
decltype(auto) get() &&;
protected:
task_base(task_promise<T>* initial = nullptr) noexcept : promise(initial)
{
}
template <typename D>
D& assign(D* self, task_base&& other) noexcept
{
static_cast<task_base&>(*this) = wistd::move(other);
return *self;
}
private:
promise_ptr<T> promise;
static void __stdcall wake_by_address(void* completed);
};
} // namespace wil::details::coro
/// @endcond
namespace wil
{
// Must write out both classes separately
// Cannot use deduction guides with alias template type prior to C++20.
template <typename T>
struct task : details::coro::task_base<T>
{
using base = details::coro::task_base<T>;
// Constructing from task_promise<T>* cannot be explicit because get_return_object relies on implicit conversion.
task(details::coro::task_promise<T>* initial = nullptr) noexcept : base(initial)
{
}
explicit task(base&& other) noexcept : base(wistd::move(other))
{
}
task& operator=(base&& other) noexcept
{
return base::assign(this, wistd::move(other));
}
using base::operator co_await;
auto operator co_await() && noexcept
{
return wistd::move(*this).resume_any_thread();
}
};
template <typename T>
struct com_task : details::coro::task_base<T>
{
using base = details::coro::task_base<T>;
// Constructing from task_promise<T>* cannot be explicit because get_return_object relies on implicit conversion.
com_task(details::coro::task_promise<T>* initial = nullptr) noexcept : base(initial)
{
}
explicit com_task(base&& other) noexcept : base(wistd::move(other))
{
}
com_task& operator=(base&& other) noexcept
{
return base::assign(this, wistd::move(other));
}
using base::operator co_await;
auto operator co_await() && noexcept
{
// You must #include <ole2.h> before <wil/coroutine.h> to enable non-agile awaiting.
return wistd::move(*this).resume_same_apartment();
}
};
template <typename T>
task(com_task<T>&&) -> task<T>;
template <typename T>
com_task(task<T>&&) -> com_task<T>;
} // namespace wil
template <typename T, typename... Args>
struct __WI_COROUTINE_NAMESPACE::coroutine_traits<wil::task<T>, Args...>
{
using promise_type = wil::details::coro::task_promise<T>;
};
template <typename T, typename... Args>
struct __WI_COROUTINE_NAMESPACE::coroutine_traits<wil::com_task<T>, Args...>
{
using promise_type = wil::details::coro::task_promise<T>;
};
#endif // __WIL_COROUTINE_INCLUDED
// Can re-include this header after including synchapi.h (usually via windows.h) to enable synchronous wait.
#if defined(_SYNCHAPI_H_) && !defined(__WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED)
#define __WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED
namespace wil::details::coro
{
template <typename T>
decltype(auto) task_base<T>::get() &&
{
if (!promise->client_await_ready())
{
bool completed = false;
if (promise->client_await_suspend(&completed, wake_by_address))
{
bool pending = false;
while (!completed)
{
WaitOnAddress(&completed, &pending, sizeof(pending), INFINITE);
}
}
}
return std::exchange(promise, {})->client_await_resume();
}
template <typename T>
void __stdcall task_base<T>::wake_by_address(void* completed)
{
*reinterpret_cast<bool*>(completed) = true;
WakeByAddressSingle(completed);
}
} // namespace wil::details::coro
#endif // __WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED
// Can re-include this header after including COM header files to enable non-agile tasks.
#if defined(_COMBASEAPI_H_) && defined(_THREADPOOLAPISET_H_) && !defined(__WIL_COROUTINE_NON_AGILE_INCLUDED)
#define __WIL_COROUTINE_NON_AGILE_INCLUDED
#include <ctxtcall.h>
#include <wil/com.h>
#include <roerrorapi.h>
namespace wil::details::coro
{
inline void* __stdcall CaptureRestrictedErrorInformation() noexcept
{
IRestrictedErrorInfo* restrictedError = nullptr;
(void)GetRestrictedErrorInfo(&restrictedError);
return restrictedError; // the returned object includes a strong reference
}
inline void __stdcall RestoreRestrictedErrorInformation(_In_ void* restricted_error) noexcept
{
(void)SetRestrictedErrorInfo(static_cast<IRestrictedErrorInfo*>(restricted_error));
}
inline void __stdcall DestroyRestrictedErrorInformation(_In_ void* restricted_error) noexcept
{
static_cast<IUnknown*>(restricted_error)->Release();
}
struct apartment_info
{
APTTYPE aptType{};
APTTYPEQUALIFIER aptTypeQualifier{};
void load()
{
if (FAILED(CoGetApartmentType(&aptType, &aptTypeQualifier)))
{
// If COM is not initialized, then act as if we are running
// on the implicit MTA.
aptType = APTTYPE_MTA;
aptTypeQualifier = APTTYPEQUALIFIER_IMPLICIT_MTA;
}
}
};
// apartment_resumer resumes a coroutine in a captured apartment.
struct apartment_resumer
{
static auto as_self(void* p)
{
return reinterpret_cast<apartment_resumer*>(p);
}
static bool is_sta()
{
apartment_info info;
info.load();
switch (info.aptType)
{
case APTTYPE_STA:
case APTTYPE_MAINSTA:
return true;
case APTTYPE_NA:
return info.aptTypeQualifier == APTTYPEQUALIFIER_NA_ON_STA || info.aptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MAINSTA;
default:
return false;
}
}
static wil::com_ptr<IContextCallback> current_context()
{
wil::com_ptr<IContextCallback> context;
// This will fail if COM is not initialized. Treat as implicit MTA.
// Do not use IID_PPV_ARGS to avoid ambiguity between ::IUnknown and winrt::IUnknown.
CoGetObjectContext(__uuidof(IContextCallback), reinterpret_cast<void**>(&context));
return context;
}
__WI_COROUTINE_NAMESPACE::coroutine_handle<> waiter;
wil::com_ptr<IContextCallback> context{nullptr};
apartment_info info{};
HRESULT resume_result = S_OK;
void capture_context(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle)
{
waiter = handle;
info.load();
context = current_context();
if (context == nullptr)
{
__debugbreak();
}
}
static void __stdcall resume_in_context(void* parameter)
{
auto self = as_self(parameter);
if (self->context == nullptr || self->context == current_context())
{
self->context = nullptr; // removes the context cleanup from the resume path
self->waiter();
}
else if (is_sta())
{
submit_threadpool_callback(resume_context, self);
}
else
{
self->resume_context_sync();
}
}
static void submit_threadpool_callback(PTP_SIMPLE_CALLBACK callback, void* context)
{
THROW_IF_WIN32_BOOL_FALSE(TrySubmitThreadpoolCallback(callback, context, nullptr));
}
static void CALLBACK resume_context(PTP_CALLBACK_INSTANCE /*instance*/, void* parameter)
{
as_self(parameter)->resume_context_sync();
}
void resume_context_sync()
{
ComCallData data{};
data.pUserDefined = this;
// The call to resume_apartment_callback will destruct the context.
// Capture into a local so we don't destruct it while it's in use.
// This also removes the context cleanup from the resume path.
auto local_context = wistd::move(context);
auto result =
local_context->ContextCallback(resume_apartment_callback, &data, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);
if (FAILED(result))
{
// Unable to resume on the correct apartment.
// Resume on the wrong apartment, but tell the coroutine why.
resume_result = result;
waiter();
}
}
static HRESULT CALLBACK resume_apartment_callback(ComCallData* data) noexcept
{
as_self(data->pUserDefined)->waiter();
return S_OK;
}
void check()
{
THROW_IF_FAILED(resume_result);
}
};
// The COM awaiter captures the COM context when the co_await begins.
// When the co_await completes, it uses that COM context to resume execution.
// This follows the same algorithm employed by C++/WinRT, which has features like
// avoiding stack buildup and proper handling of the neutral apartment.
// It does, however, introduce fail-fast code paths if thread pool tasks cannot
// be submitted. (Those fail-fasts could be removed by preallocating the tasks,
// but that means paying an up-front cost for something that may never end up used,
// as well as introducing extra cleanup code in the fast-path.)
template <typename T>
struct com_awaiter : agile_awaiter<T>
{
com_awaiter(promise_ptr<T>&& initial) : agile_awaiter<T>(wistd::move(initial))
{
}
apartment_resumer resumer;
auto await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle)
{
resumer.capture_context(handle);
return this->promise->client_await_suspend(wistd::addressof(resumer), apartment_resumer::resume_in_context);
}
decltype(auto) await_resume()
{
resumer.check();
return agile_awaiter<T>::await_resume();
}
};
template <typename T>
auto task_base<T>::resume_same_apartment() && noexcept
{
return com_awaiter<T>{wistd::move(promise)};
}
} // namespace wil::details::coro
// This section is lit up when COM headers are available. Initialize the global function
// pointers such that error information can be saved and restored across thread boundaries.
WI_HEADER_INITIALIZATION_FUNCTION(CoroutineRestrictedErrorInitialize, [] {
::wil::details::coro::g_pfnCaptureRestrictedErrorInformation = ::wil::details::coro::CaptureRestrictedErrorInformation;
::wil::details::coro::g_pfnRestoreRestrictedErrorInformation = ::wil::details::coro::RestoreRestrictedErrorInformation;
::wil::details::coro::g_pfnDestroyRestrictedErrorInformation = ::wil::details::coro::DestroyRestrictedErrorInformation;
return 1;
})
#endif // __WIL_COROUTINE_NON_AGILE_INCLUDED

499
d3d11.x/wil/cppwinrt.h Normal file
View File

@@ -0,0 +1,499 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Error Handling Helpers: support for interoperability between WIL and C++/WinRT exception-to-HRESULT logic.
#ifndef __WIL_CPPWINRT_INCLUDED
#define __WIL_CPPWINRT_INCLUDED
#include "common.h"
#include <windows.h>
#include <unknwn.h>
#include <inspectable.h>
#include <hstring.h>
// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to
// understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to
// C++/WinRT "2.0" this was accomplished by injecting the WINRT_EXTERNAL_CATCH_CLAUSE macro - that WIL defines below -
// into its exception handler (winrt::to_hresult). Starting with C++/WinRT "2.0" this mechanism has shifted to a global
// function pointer - winrt_to_hresult_handler - that WIL sets automatically when this header is included and
// 'CPPWINRT_SUPPRESS_STATIC_INITIALIZERS' is not defined.
/// @cond
namespace wil::details
{
// Since the C++/WinRT version macro is a string...
// For example: "2.0.221104.6"
inline constexpr int version_from_string(const char* versionString)
{
int result = 0;
while ((*versionString >= '0') && (*versionString <= '9'))
{
result = result * 10 + (*versionString - '0');
++versionString;
}
return result;
}
inline constexpr int major_version_from_string(const char* versionString)
{
return version_from_string(versionString);
}
inline constexpr int minor_version_from_string(const char* versionString)
{
int dotCount = 0;
while ((*versionString != '\0'))
{
if (*versionString == '.')
{
++dotCount;
}
++versionString;
if (dotCount == 2)
{
return version_from_string(versionString);
}
}
return 0;
}
} // namespace wil::details
/// @endcond
#ifdef CPPWINRT_VERSION
// Prior to C++/WinRT "2.0" this header needed to be included before 'winrt/base.h' so that our definition of
// 'WINRT_EXTERNAL_CATCH_CLAUSE' would get picked up in the implementation of 'winrt::to_hresult'. This is no longer
// problematic, so only emit an error when using a version of C++/WinRT prior to 2.0
static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, "Please include wil/cppwinrt.h before including any C++/WinRT headers");
#endif
// NOTE: Will eventually be removed once C++/WinRT 2.0 use can be assumed
/// @cond
#ifdef WINRT_EXTERNAL_CATCH_CLAUSE
#define __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 1
#else
#define WINRT_EXTERNAL_CATCH_CLAUSE \
catch (const wil::ResultException& e) \
{ \
return winrt::hresult_error(e.GetErrorCode(), winrt::to_hstring(e.what())).to_abi(); \
}
#endif
/// @endcond
#include "result_macros.h"
#include <winrt/base.h>
#if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE
static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, "C++/WinRT external catch clause already defined outside of WIL");
#endif
/// @cond
// In C++/WinRT 2.0 and beyond, this function pointer exists. In earlier versions it does not. It's much easier to avoid
// linker errors than it is to SFINAE on variable existence, so we declare the variable here, but are careful not to
// use it unless the version of C++/WinRT is high enough
extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept;
// The same is true with this function pointer as well, except that the version must be 2.X or higher.
extern void(__stdcall* winrt_throw_hresult_handler)(uint32_t, char const*, char const*, void*, winrt::hresult const) noexcept;
/// @endcond
/// @cond
namespace wil::details
{
inline void MaybeGetExceptionString(
const winrt::hresult_error& exception,
_Out_writes_opt_(debugStringChars) PWSTR debugString,
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
{
if (debugString)
{
StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str());
}
}
inline HRESULT __stdcall ResultFromCaughtException_CppWinRt(
_Inout_updates_opt_(debugStringChars) PWSTR debugString,
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
_Inout_ bool* isNormalized) noexcept
{
if (g_pfnResultFromCaughtException)
{
try
{
throw;
}
catch (const ResultException& exception)
{
*isNormalized = true;
MaybeGetExceptionString(exception, debugString, debugStringChars);
return exception.GetErrorCode();
}
catch (const winrt::hresult_error& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return exception.to_abi();
}
catch (const std::bad_alloc& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_OUTOFMEMORY;
}
catch (const std::out_of_range& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_BOUNDS;
}
catch (const std::invalid_argument& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_INVALIDARG;
}
catch (...)
{
auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
if (FAILED(hr))
{
return hr;
}
}
}
else
{
try
{
throw;
}
catch (const ResultException& exception)
{
*isNormalized = true;
MaybeGetExceptionString(exception, debugString, debugStringChars);
return exception.GetErrorCode();
}
catch (const winrt::hresult_error& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return exception.to_abi();
}
catch (const std::bad_alloc& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_OUTOFMEMORY;
}
catch (const std::out_of_range& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_BOUNDS;
}
catch (const std::invalid_argument& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return E_INVALIDARG;
}
catch (const std::exception& exception)
{
MaybeGetExceptionString(exception, debugString, debugStringChars);
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
}
catch (...)
{
// Fall through to returning 'S_OK' below
}
}
// Tell the caller that we were unable to map the exception by succeeding...
return S_OK;
}
} // namespace wil::details
/// @endcond
namespace wil
{
inline std::int32_t __stdcall winrt_to_hresult(void* returnAddress) noexcept
{
// C++/WinRT only gives us the return address (caller), so pass along an empty 'DiagnosticsInfo' since we don't
// have accurate file/line/etc. information
return static_cast<std::int32_t>(
details::ReportFailure_CaughtException<FailureType::Return>(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress)));
}
inline void __stdcall winrt_throw_hresult(
uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
{
void* callerReturnAddress{nullptr};
PCSTR code{nullptr};
wil::details::ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL __R_COMMA result);
}
inline void WilInitialize_CppWinRT()
{
details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt;
if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2)
{
WI_ASSERT(winrt_to_hresult_handler == nullptr);
winrt_to_hresult_handler = winrt_to_hresult;
if constexpr (details::minor_version_from_string(CPPWINRT_VERSION) >= 210122)
{
WI_ASSERT(winrt_throw_hresult_handler == nullptr);
winrt_throw_hresult_handler = winrt_throw_hresult;
}
}
}
/// @cond
namespace details
{
#ifndef CPPWINRT_SUPPRESS_STATIC_INITIALIZERS
WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "0")
WI_HEADER_INITIALIZATION_FUNCTION(WilInitialize_CppWinRT, [] {
::wil::WilInitialize_CppWinRT();
return 1;
});
#else
WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1")
#endif
} // namespace details
/// @endcond
// Provides an overload of verify_hresult so that the WIL macros can recognize winrt::hresult as a valid "hresult" type.
inline long verify_hresult(winrt::hresult hr) noexcept
{
return hr;
}
// Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience.
template <typename T>
auto get_abi(T const& object) noexcept
{
return winrt::get_abi(object);
}
inline auto get_abi(winrt::hstring const& object) noexcept
{
return static_cast<HSTRING>(winrt::get_abi(object));
}
inline auto str_raw_ptr(const winrt::hstring& str) noexcept
{
return str.c_str();
}
template <typename T>
auto put_abi(T& object) noexcept
{
return winrt::put_abi(object);
}
inline auto put_abi(winrt::hstring& object) noexcept
{
return reinterpret_cast<HSTRING*>(winrt::put_abi(object));
}
inline ::IUnknown* com_raw_ptr(const winrt::Windows::Foundation::IUnknown& ptr) noexcept
{
return static_cast<::IUnknown*>(winrt::get_abi(ptr));
}
// Needed to power wil::cx_object_from_abi that requires IInspectable
inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectable& ptr) noexcept
{
return static_cast<::IInspectable*>(winrt::get_abi(ptr));
}
// Taken from the docs.microsoft.com article
template <typename T>
T convert_from_abi(::IUnknown* from)
{
T to{nullptr}; // `T` is a projected type.
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(to)));
return to;
}
// For obtaining an object from an interop method on the factory. Example:
// winrt::InputPane inputPane = wil::capture_interop<winrt::InputPane>(&IInputPaneInterop::GetForWindow, hwnd);
// If the method produces something different from the factory type:
// winrt::IAsyncAction action = wil::capture_interop<winrt::IAsyncAction, winrt::AccountsSettingsPane>(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd);
template <typename WinRTResult, typename WinRTFactory = WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args)
{
auto interop = winrt::get_activation_factory<WinRTFactory, Interface>();
return winrt::capture<WinRTResult>(interop, method, std::forward<Args>(args)...);
}
// For obtaining an object from an interop method on an instance. Example:
// winrt::UserActivitySession session = wil::capture_interop<winrt::UserActivitySession>(activity, &IUserActivityInterop::CreateSessionForWindow, hwnd);
template <typename WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
auto capture_interop(winrt::Windows::Foundation::IUnknown const& o, HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args)
{
return winrt::capture<WinRTResult>(o.as<Interface>(), method, std::forward<Args>(args)...);
}
/** Holds a reference to the host C++/WinRT module to prevent it from being unloaded.
Normally, this is done by being in an IAsyncOperation coroutine or by holding a strong
reference to a C++/WinRT object hosted in the same module, but if you have neither,
you will need to hold a reference explicitly. For the WRL equivalent, see wrl_module_reference.
This can be used as a base, which permits EBO:
@code
struct NonWinrtObject : wil::winrt_module_reference
{
int value;
};
// DLL will not be unloaded as long as NonWinrtObject is still alive.
auto p = std::make_unique<NonWinrtObject>();
@endcode
Or it can be used as a member (with [[no_unique_address]] to avoid
occupying any memory):
@code
struct NonWinrtObject
{
int value;
[[no_unique_address]] wil::winrt_module_reference module_ref;
};
// DLL will not be unloaded as long as NonWinrtObject is still alive.
auto p = std::make_unique<NonWinrtObject>();
@endcode
If using it to prevent the host DLL from unloading while a thread
or threadpool work item is still running, create the object before
starting the thread, and pass it to the thread. This avoids a race
condition where the host DLL could get unloaded before the thread starts.
@code
std::thread([module_ref = wil::winrt_module_reference()]() { do_background_work(); });
// Don't do this (race condition)
std::thread([]() { wil::winrt_module_reference module_ref; do_background_work(); }); // WRONG
@endcode
Also useful in coroutines that neither capture DLL-hosted COM objects, nor are themselves
DLL-hosted COM objects. (If the coroutine returns IAsyncAction or captures a get_strong()
of its containing WinRT class, then the IAsyncAction or strong reference will itself keep
a strong reference to the host module.)
@code
winrt::fire_and_forget ContinueBackgroundWork()
{
// prevent DLL from unloading while we are running on a background thread.
// Do this before switching to the background thread.
wil::winrt_module_reference module_ref;
co_await winrt::resume_background();
do_background_work();
};
@endcode
*/
struct [[nodiscard]] winrt_module_reference
{
winrt_module_reference()
{
++winrt::get_module_lock();
}
winrt_module_reference(winrt_module_reference const&) : winrt_module_reference()
{
}
~winrt_module_reference()
{
--winrt::get_module_lock();
}
};
/** Implements a C++/WinRT class where some interfaces are conditionally supported.
@code
// Assume the existence of a class "Version2" which says whether
// the IMyThing2 interface should be supported.
struct Version2 { static bool IsEnabled(); };
// Declare implementation class which conditionally supports IMyThing2.
struct MyThing : wil::winrt_conditionally_implements<MyThingT<MyThing>,
Version2, IMyThing2>
{
// implementation goes here
};
@endcode
If `Version2::IsEnabled()` returns `false`, then the `QueryInterface`
for `IMyThing2` will fail.
Any interface not listed as conditional is assumed to be enabled unconditionally.
You can add additional Version / Interface pairs to the template parameter list.
Interfaces may be conditionalized on at most one Version class. If you need a
complex conditional, create a new helper class.
@code
// Helper class for testing two Versions.
struct Version2_or_greater {
static bool IsEnabled() { return Version2::IsEnabled() || Version3::IsEnabled(); }
};
// This implementation supports IMyThing2 if either Version2 or Version3 is enabled,
// and supports IMyThing3 only if Version3 is enabled.
struct MyThing : wil::winrt_conditionally_implements<MyThingT<MyThing>,
Version2_or_greater, IMyThing2, Version3, IMyThing3>
{
// implementation goes here
};
@endcode
*/
template <typename Implements, typename... Rest>
struct winrt_conditionally_implements : Implements
{
using Implements::Implements;
void* find_interface(winrt::guid const& iid) const noexcept override
{
static_assert(sizeof...(Rest) % 2 == 0, "Extra template parameters should come in groups of two");
if (is_enabled<0, std::tuple<Rest...>>(iid))
{
return Implements::find_interface(iid);
}
return nullptr;
}
private:
template <std::size_t index, typename Tuple>
static bool is_enabled(winrt::guid const& iid)
{
if constexpr (index >= std::tuple_size_v<Tuple>)
{
return true;
}
else
{
check_no_duplicates<1, index + 1, Tuple>();
return (iid == winrt::guid_of<std::tuple_element_t<index + 1, Tuple>>()) ? std::tuple_element_t<index, Tuple>::IsEnabled()
: is_enabled<index + 2, Tuple>(iid);
}
}
template <std::size_t index, std::size_t upto, typename Tuple>
static constexpr void check_no_duplicates()
{
if constexpr (index < upto)
{
static_assert(
!std::is_same_v<std::tuple_element_t<index, Tuple>, std::tuple_element_t<upto, Tuple>>,
"Duplicate interfaces found in winrt_conditionally_implements");
check_no_duplicates<index + 2, upto, Tuple>();
}
}
};
} // namespace wil
#endif // __WIL_CPPWINRT_INCLUDED

View File

@@ -0,0 +1,334 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Helpers that make authoring C++/WinRT components easier.
namespace wil
{
#ifndef __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
/// @cond
#define __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
namespace details
{
template <typename T>
struct single_threaded_property_storage
{
T m_value{};
single_threaded_property_storage() = default;
single_threaded_property_storage(const T& value) : m_value(value)
{
}
operator T&()
{
return m_value;
}
operator T const&() const
{
return m_value;
}
template <typename Q>
auto operator=(Q&& q)
{
m_value = wistd::forward<Q>(q);
return *this;
}
};
} // namespace details
/// @endcond
template <typename T>
struct single_threaded_property
: std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>, wil::details::single_threaded_property_storage<T>, T>
{
single_threaded_property() = default;
template <typename... TArgs>
single_threaded_property(TArgs&&... value) : base_type(std::forward<TArgs>(value)...)
{
}
using base_type =
std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>, wil::details::single_threaded_property_storage<T>, T>;
T operator()() const
{
return *this;
}
// This is the only setter exposed. We don't expose `operator()(Q&& q)`,
// since that is what C++/WinRT uses to implement public setters. Since
// single_threaded_property is intended for readonly properties, we
// don't want to expose that.
//
// To set the value of this property *internally* (within your
// implementation), use this `operator=`:
//
// MyProperty = 42;
// // MyProperty(42); // won't work
//
// For settable properties, use single_threaded_rw_property<T> instead.
template <typename Q>
auto& operator=(Q&& q)
{
static_cast<base_type&>(*this) = std::forward<Q>(q);
return *this;
}
};
template <typename T>
struct single_threaded_rw_property : single_threaded_property<T>
{
using base_type = single_threaded_property<T>;
template <typename... TArgs>
single_threaded_rw_property(TArgs&&... value) : base_type(std::forward<TArgs>(value)...)
{
}
using base_type::operator();
// needed in lieu of deducing-this
template <typename Q>
auto& operator()(Q&& q)
{
return *this = std::forward<Q>(q);
}
// needed in lieu of deducing-this
template <typename Q>
auto& operator=(Q&& q)
{
base_type::operator=(std::forward<Q>(q));
return *this;
}
};
#endif // __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)) || \
defined(WIL_DOXYGEN) // WinRT / XAML helpers
/// @cond
#define __WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION
namespace details
{
template <typename T>
struct event_base
{
winrt::event_token operator()(const T& handler)
{
return m_handler.add(handler);
}
auto operator()(const winrt::event_token& token) noexcept
{
return m_handler.remove(token);
}
template <typename... TArgs>
auto invoke(TArgs&&... args)
{
return m_handler(std::forward<TArgs>(args)...);
}
private:
winrt::event<T> m_handler;
};
} // namespace details
/// @endcond
/**
* @brief A default event handler that maps to
* [Windows.Foundation.EventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.eventhandler-1).
* @tparam T The event data type.
*/
template <typename T>
struct untyped_event : wil::details::event_base<winrt::Windows::Foundation::EventHandler<T>>
{
};
/**
* @brief A default event handler that maps to
* [Windows.Foundation.TypedEventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.typedeventhandler-2).
* @tparam T The event data type.
* @details Usage example:
* @code
* // In IDL, this corresponds to:
* // event Windows.Foundation.TypedEventHandler<ModalPage, String> OkClicked;
* wil::typed_event<MarkupSample::ModalPage, winrt::hstring> OkClicked;
* @endcode
*/
template <typename TSender, typename TArgs>
struct typed_event : wil::details::event_base<winrt::Windows::Foundation::TypedEventHandler<TSender, TArgs>>
{
};
#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || defined(WINRT_Windows_UI_Xaml_Data_H))) || \
defined(WIL_DOXYGEN) // INotifyPropertyChanged helpers
/// @cond
#define __WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA
namespace details
{
#ifdef WINRT_Microsoft_UI_Xaml_Data_H
using Xaml_Data_PropertyChangedEventHandler = winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler;
using Xaml_Data_PropertyChangedEventArgs = winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventArgs;
#elif defined(WINRT_Windows_UI_Xaml_Data_H)
using Xaml_Data_PropertyChangedEventHandler = winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler;
using Xaml_Data_PropertyChangedEventArgs = winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs;
#endif
} // namespace details
/// @endcond
/**
* @brief Helper base class to inherit from to have a simple implementation of
* [INotifyPropertyChanged](https://docs.microsoft.com/uwp/api/windows.ui.xaml.data.inotifypropertychanged).
* @tparam T CRTP type
* @details When you declare your class, make this class a base class and pass your class as a template parameter:
* @code
* struct MyPage : MyPageT<MyPage>, wil::notify_property_changed_base<MyPage>
* {
* wil::single_threaded_notifying_property<int> MyInt;
* MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { }
* // or
* WIL_NOTIFYING_PROPERTY(int, MyInt, 42);
* };
* @endcode
*/
template <typename T, typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler, typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
struct notify_property_changed_base
{
using Type = T;
auto PropertyChanged(Xaml_Data_PropertyChangedEventHandler const& value)
{
return m_propertyChanged.add(value);
}
void PropertyChanged(winrt::event_token const& token)
{
m_propertyChanged.remove(token);
}
Type& self()
{
return *static_cast<Type*>(this);
}
/**
* @brief Raises a property change notification event
* @param name The name of the property
* @return
* @details Usage example\n
* C++
* @code
* void MyPage::DoSomething()
* {
* // modify MyInt
* // MyInt = ...
*
* // now send a notification to update the bound UI elements
* RaisePropertyChanged(L"MyInt");
* }
* @endcode
*/
auto RaisePropertyChanged(std::wstring_view name)
{
return m_propertyChanged(self(), Xaml_Data_PropertyChangedEventArgs{name});
}
protected:
winrt::event<Xaml_Data_PropertyChangedEventHandler> m_propertyChanged;
};
/**
* @brief Implements a property type with notifications
* @tparam T the property type
* @details Use the INIT_NOTIFY_PROPERTY macro to initialize this property in your class constructor. This will set up the
* right property name, and bind it to the `notify_property_changed_base` implementation.
*/
template <typename T, typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler, typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
struct single_threaded_notifying_property : single_threaded_rw_property<T>
{
using Type = T;
using base_type = single_threaded_rw_property<T>;
using base_type::operator();
template <typename Q>
auto& operator()(Q&& q)
{
return *this = std::forward<Q>(q);
}
template <typename Q>
auto& operator=(Q&& q)
{
if (q != this->operator()())
{
static_cast<base_type&>(*this) = std::forward<Q>(q);
if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr))
{
(*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{m_name});
}
}
return *this;
}
template <typename... TArgs>
single_threaded_notifying_property(
winrt::event<Xaml_Data_PropertyChangedEventHandler>* npc,
const winrt::Windows::Foundation::IInspectable& sender,
std::wstring_view name,
TArgs&&... args) :
single_threaded_rw_property<T>(std::forward<TArgs...>(args)...), m_name(name), m_npc(npc), m_sender(sender)
{
}
single_threaded_notifying_property(const single_threaded_notifying_property&) = default;
single_threaded_notifying_property(single_threaded_notifying_property&&) = default;
std::wstring_view Name() const noexcept
{
return m_name;
}
private:
std::wstring_view m_name;
winrt::event<Xaml_Data_PropertyChangedEventHandler>* m_npc;
winrt::weak_ref<winrt::Windows::Foundation::IInspectable> m_sender;
};
/**
* @def WIL_NOTIFYING_PROPERTY
* @brief use this to stamp out a property that calls RaisePropertyChanged upon changing its value. This is a zero-storage
* alternative to wil::single_threaded_notifying_property<T>.
* @details You can pass an initializer list for the initial property value in the variadic arguments to this macro.
*/
#define WIL_NOTIFYING_PROPERTY(type, name, ...) \
type m_##name{__VA_ARGS__}; \
auto name() const noexcept \
{ \
return m_##name; \
} \
auto& name(type value) \
{ \
if (m_##name != value) \
{ \
m_##name = std::move(value); \
RaisePropertyChanged(L"" #name); \
} \
return *this; \
}
/**
* @def INIT_NOTIFYING_PROPERTY
* @brief use this to initialize a wil::single_threaded_notifying_property in your class constructor.
*/
#define INIT_NOTIFYING_PROPERTY(NAME, VALUE) NAME(&m_propertyChanged, *this, L"" #NAME, VALUE)
#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || defined(WINRT_Windows_UI_Xaml_Data_H))
} // namespace wil

View File

@@ -0,0 +1,393 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Helpers for common patterns and tasks when using C++/WinRT.
#ifndef __WIL_CPPWINRT_HELPERS_DEFINED
#define __WIL_CPPWINRT_HELPERS_DEFINED
/// @cond
namespace wil::details
{
struct dispatcher_RunAsync
{
template <typename Dispatcher, typename... Args>
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
{
dispatcher.RunAsync(std::forward<Args>(args)...);
}
};
struct dispatcher_TryEnqueue
{
template <typename Dispatcher, typename... Args>
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
{
dispatcher.TryEnqueue(std::forward<Args>(args)...);
}
};
template <typename Dispatcher>
struct dispatcher_traits;
} // namespace wil::details
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
#include <experimental/coroutine>
namespace wil::details
{
template <typename T = void>
using coroutine_handle = std::experimental::coroutine_handle<T>;
}
#elif defined(__cpp_impl_coroutine)
#include <coroutine>
#if (__cpp_lib_coroutine >= 201902L)
namespace wil::details
{
template <typename T = void>
using coroutine_handle = std::coroutine_handle<T>;
}
#endif // __cpp_lib_coroutine
#endif // __cpp_impl_coroutine
/// @endcond
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || \
(defined(__cpp_impl_coroutine) && defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L))
/// @cond
namespace wil::details
{
struct dispatched_handler_state
{
details::coroutine_handle<> handle{};
bool orphaned = false;
};
struct dispatcher_handler
{
dispatcher_handler(dispatched_handler_state* state) : m_state(state)
{
}
dispatcher_handler(dispatcher_handler&& other) noexcept : m_state(std::exchange(other.m_state, {}))
{
}
~dispatcher_handler()
{
if (m_state && m_state->handle)
{
m_state->orphaned = true;
Complete();
}
}
void operator()()
{
Complete();
}
void Complete()
{
auto state = std::exchange(m_state, nullptr);
std::exchange(state->handle, {}).resume();
}
dispatched_handler_state* m_state;
};
} // namespace wil::details
/// @endcond
namespace wil
{
//! Resumes coroutine execution on the thread associated with the dispatcher, or throws
//! an exception (from an arbitrary thread) if unable. Supported dispatchers are
//! Windows.System.DispatcherQueue, Microsoft.System.DispatcherQueue,
//! Microsoft.UI.Dispatching.DispatcherQueue, and Windows.UI.Core.CoreDispatcher,
//! but you must include the corresponding <winrt/Namespace.h> header before including
//! wil/cppwinrt_helpers.h. It is okay to include wil/cppwinrt_helpers.h multiple times:
//! support will be enabled for any winrt/Namespace.h headers that were included since
//! the previous inclusion of wil/cppwinrt_headers.h.
template <typename Dispatcher>
[[nodiscard]] auto resume_foreground(
Dispatcher const& dispatcher,
typename details::dispatcher_traits<Dispatcher>::Priority priority = details::dispatcher_traits<Dispatcher>::Priority::Normal)
{
using Traits = details::dispatcher_traits<Dispatcher>;
using Priority = typename Traits::Priority;
using Handler = typename Traits::Handler;
struct awaitable
{
awaitable(Dispatcher const& dispatcher, Priority priority) noexcept : m_dispatcher(dispatcher), m_priority(priority)
{
}
bool await_ready() const noexcept
{
return false;
}
void await_suspend(details::coroutine_handle<> handle)
{
m_state.handle = handle;
Handler handler{details::dispatcher_handler(&m_state)};
try
{
// The return value of Schedule is not reliable. Use the dispatcher_handler destructor
// to detect whether the work item failed to run.
Traits::Scheduler::Schedule(m_dispatcher, m_priority, handler);
}
catch (...)
{
m_state.handle = nullptr; // the exception will resume the coroutine, so the handler shouldn't do it
throw;
}
}
void await_resume() const
{
if (m_state.orphaned)
{
throw winrt::hresult_error(static_cast<winrt::hresult>(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE)
}
}
private:
Dispatcher const& m_dispatcher;
Priority const m_priority;
details::dispatched_handler_state m_state;
};
return awaitable{dispatcher, priority};
}
} // namespace wil
#endif // Coroutines are supported
#endif // __WIL_CPPWINRT_HELPERS_DEFINED
/// @cond
#if defined(WINRT_Windows_UI_Core_H) && !defined(__WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
namespace wil::details
{
template <>
struct dispatcher_traits<winrt::Windows::UI::Core::CoreDispatcher>
{
using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority;
using Handler = winrt::Windows::UI::Core::DispatchedHandler;
using Scheduler = dispatcher_RunAsync;
};
} // namespace wil::details
#endif // __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
#if defined(WINRT_Windows_System_H) && !defined(__WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS)
#define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
namespace wil::details
{
template <>
struct dispatcher_traits<winrt::Windows::System::DispatcherQueue>
{
using Priority = winrt::Windows::System::DispatcherQueuePriority;
using Handler = winrt::Windows::System::DispatcherQueueHandler;
using Scheduler = dispatcher_TryEnqueue;
};
} // namespace wil::details
#endif // __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
#if defined(WINRT_Microsoft_System_H) && !defined(__WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS)
#define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
namespace wil::details
{
template <>
struct dispatcher_traits<winrt::Microsoft::System::DispatcherQueue>
{
using Priority = winrt::Microsoft::System::DispatcherQueuePriority;
using Handler = winrt::Microsoft::System::DispatcherQueueHandler;
using Scheduler = dispatcher_TryEnqueue;
};
} // namespace wil::details
#endif // __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
#if defined(WINRT_Microsoft_UI_Dispatching_H) && !defined(__WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS)
#define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
namespace wil::details
{
template <>
struct dispatcher_traits<winrt::Microsoft::UI::Dispatching::DispatcherQueue>
{
using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority;
using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler;
using Scheduler = dispatcher_TryEnqueue;
};
} // namespace wil::details
#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
/// @endcond
#if (defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)) || \
defined(WIL_DOXYGEN)
/// @cond
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS
/// @endcond
namespace wil
{
/// @cond
namespace details
{
template <typename T>
struct is_winrt_vector_like
{
private:
template <
typename U,
typename = decltype(std::declval<U>().GetMany(std::declval<U>().Size(), winrt::array_view<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>
struct is_winrt_iterator_like
{
private:
template <typename U, typename = decltype(std::declval<U>().GetMany(winrt::array_view<decltype(std::declval<U>().Current())>{}))>
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>
constexpr T empty() noexcept
{
if constexpr (std::is_base_of_v<winrt::Windows::Foundation::IUnknown, T>)
{
return nullptr;
}
else
{
return {};
}
}
} // namespace details
/// @endcond
/** Converts C++ / WinRT vectors, iterators, and iterables to std::vector by requesting the
collection's data in bulk. This can be more efficient in terms of IPC cost than iteratively
processing the collection.
@code
winrt::IVector<winrt::hstring> collection = GetCollection();
std::vector<winrt::hstring> allData = wil::to_vector(collection); // read all data from collection
for (winrt::hstring const& item : allData)
{
// use item
}
@endcode
Can be used for IVector<T>, IVectorView<T>, IIterable<T>, IIterator<T>, and any type or
interface that C++/WinRT projects those interfaces for (PropertySet, IMap<T,K>, etc.)
Iterable-only types fetch content in units of 64. When used with an iterator, the returned
vector contains the iterator's current position and any others after it.
*/
template <typename TSrc>
auto to_vector(TSrc const& src)
{
if constexpr (details::is_winrt_vector_like<TSrc>::value)
{
using T = decltype(src.GetAt(0));
std::vector<T> result;
if (auto expected = src.Size())
{
result.resize(expected + 1, details::empty<T>());
auto actual = src.GetMany(0, result);
if (actual > expected)
{
throw winrt::hresult_changed_state();
}
result.resize(actual, details::empty<T>());
}
return result;
}
else if constexpr (details::is_winrt_iterator_like<TSrc>::value)
{
using T = decltype(src.Current());
std::vector<T> result;
constexpr uint32_t chunkSize = 64;
while (true)
{
auto const lastSize = result.size();
result.resize(lastSize + chunkSize, details::empty<T>());
auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize});
if (fetched < chunkSize)
{
result.resize(lastSize + fetched, details::empty<T>());
break;
}
}
return result;
}
else
{
return to_vector(src.First());
}
}
} // namespace wil
#endif
#if (defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS)) || \
defined(WIL_DOXYGEN)
/// @cond
#define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS
/// @endcond
#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX)
#pragma push_macro("ABI")
#undef ABI
#define ABI
#endif
namespace wil
{
#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)
//! The following methods require that you include both <winrt/Windows.UI.h>
//! <Windows.UI.Interop.h> before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION
//! is at least NTDDI_WIN10_CU. It is okay to include wil/cppwinrt_helpers.h multiple times:
//! support will be enabled for any headers that were included since the previous inclusion
//! of wil/cppwinrt_headers.h.
inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd)
{
ABI::Windows::UI::WindowId abiWindowId;
winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId));
return winrt::Windows::UI::WindowId{abiWindowId.Value};
}
inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId)
{
HWND hwnd;
winrt::check_hresult(::GetWindowFromWindowId({windowId.Value}, &hwnd));
return hwnd;
}
#endif /*defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)*/
} // namespace wil
#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX)
#pragma pop_macro("ABI")
#endif
#endif // __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS

View File

@@ -0,0 +1,112 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Utilities for implementing OOP COM server with cppwinrt only
#ifndef __WIL_CPPWINRT_NOTIFIABLE_MODULE_LOCK_INCLUDED
#define __WIL_CPPWINRT_NOTIFIABLE_MODULE_LOCK_INCLUDED
#ifdef WINRT_BASE_H
#error You must include this header before including any winrt header
#endif
#ifndef WINRT_CUSTOM_MODULE_LOCK
#error You must define 'WINRT_CUSTOM_MODULE_LOCK' at the project level
#endif
#include <atomic>
#include <cstdint>
namespace wil
{
// Adopted from cppwinrt
struct notifiable_module_lock_base
{
notifiable_module_lock_base() = default;
notifiable_module_lock_base(uint32_t count) : 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);
if (notifier) // Protect against callback not being set yet
{
notifier();
}
}
else if (remaining < 0)
{
abort();
}
return remaining;
}
operator uint32_t() const noexcept
{
return m_count;
}
template <typename Func>
void set_notifier(Func&& func)
{
notifier = std::forward<Func>(func);
}
void set_notifier(std::nullptr_t) noexcept
{
notifier = nullptr;
}
private:
std::atomic<int32_t> m_count{0};
std::function<void()> notifier{};
};
struct notifiable_module_lock final : notifiable_module_lock_base
{
static notifiable_module_lock& instance() noexcept
{
static notifiable_module_lock lock;
return lock;
}
};
} // namespace wil
#ifndef WIL_CPPWINRT_COM_SERVER_CUSTOM_MODULE_LOCK
namespace winrt
{
auto& get_module_lock()
{
return wil::notifiable_module_lock::instance();
}
} // namespace winrt
#endif
#endif

View File

@@ -0,0 +1,76 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Utilities for making managing COM server easier
#ifndef __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED
#define __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED
#include <winrt/base.h>
#include <wil/resource.h>
#include <wil/cppwinrt.h>
#include <vector>
namespace wil::details
{
template <typename T>
struct CppWinRTClassFactory : winrt::implements<CppWinRTClassFactory<T>, IClassFactory, winrt::no_module_lock>
{
HRESULT __stdcall CreateInstance(IUnknown* outer, GUID const& iid, void** result) noexcept final
try
{
*result = nullptr;
if (outer)
{
return CLASS_E_NOAGGREGATION;
}
return winrt::make_self<T>().as(iid, result);
}
CATCH_RETURN()
HRESULT __stdcall LockServer(BOOL) noexcept final
{
return S_OK;
}
};
template <typename T = void, typename... Rest>
void register_com_server(std::vector<wil::unique_com_class_object_cookie>& registrations)
{
DWORD registration{};
winrt::check_hresult(CoRegisterClassObject(
winrt::guid_of<T>(), winrt::make<CppWinRTClassFactory<T>>().get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &registration));
// This emplace_back is no-throw as wil::register_com_server already reserves enough capacity
registrations.emplace_back(registration);
register_com_server<Rest...>(registrations);
}
template <>
void register_com_server<void>(std::vector<unique_com_class_object_cookie>&)
{
}
} // namespace wil::details
namespace wil
{
template <typename T, typename... Rest>
[[nodiscard]] std::vector<wil::unique_com_class_object_cookie> register_com_server()
{
std::vector<wil::unique_com_class_object_cookie> registrations;
registrations.reserve(sizeof...(Rest) + 1);
details::register_com_server<T, Rest...>(registrations);
// C++17 doesn't provide guaranteed copy elision, but the copy should be elided nonetheless.
return registrations;
}
} // namespace wil
#endif

View File

@@ -0,0 +1,80 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Provides interoperability between C++/WinRT types and the WRL Module system.
#ifndef __WIL_CPPWINRT_WRL_INCLUDED
#define __WIL_CPPWINRT_WRL_INCLUDED
#include "cppwinrt.h"
#include <winrt/base.h>
#include "result_macros.h"
#include <wrl/module.h>
// wil::wrl_factory_for_winrt_com_class provides interopability between a
// C++/WinRT class and the WRL Module system, allowing the winrt class to be
// CoCreatable.
//
// Usage:
// - In your cpp, add:
// CoCreatableCppWinRtClass(className)
//
// - In the dll.cpp (or equivalent) for the module containing your class, add:
// CoCreatableClassWrlCreatorMapInclude(className)
//
namespace wil
{
/// @cond
namespace details
{
template <typename TCppWinRTClass>
class module_count_wrapper : public TCppWinRTClass
{
public:
module_count_wrapper()
{
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
{
modulePtr->IncrementObjectCount();
}
}
virtual ~module_count_wrapper()
{
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
{
modulePtr->DecrementObjectCount();
}
}
};
} // namespace details
/// @endcond
template <typename TCppWinRTClass>
class wrl_factory_for_winrt_com_class : public ::Microsoft::WRL::ClassFactory<>
{
public:
IFACEMETHODIMP CreateInstance(_In_opt_ ::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept
try
{
*object = nullptr;
RETURN_HR_IF(CLASS_E_NOAGGREGATION, unknownOuter != nullptr);
return winrt::make<details::module_count_wrapper<TCppWinRTClass>>().as(riid, object);
}
CATCH_RETURN()
};
} // namespace wil
#define CoCreatableCppWinRtClass(className) \
CoCreatableClassWithFactory(className, ::wil::wrl_factory_for_winrt_com_class<className>)
#endif // __WIL_CPPWINRT_WRL_INCLUDED

1333
d3d11.x/wil/filesystem.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Error Handling Helpers: supporting file defining a family of macros and functions designed to uniformly handle errors
//! across return codes, fail fast, exceptions and logging for NTSTATUS values.
#ifndef __WIL_NT_RESULTMACROS_INCLUDED
#define __WIL_NT_RESULTMACROS_INCLUDED
#include "result_macros.h"
// Helpers for return macros
/// @cond
#define __NT_RETURN_NTSTATUS(status, str) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
NTSTATUS __status = (status); \
if (FAILED_NTSTATUS(__status)) \
{ \
__R_FN(Return_NtStatus)(__R_INFO(str) __status); \
} \
return __status; \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define __NT_RETURN_NTSTATUS_MSG(status, str, fmt, ...) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
NTSTATUS __status = (status); \
if (FAILED_NTSTATUS(__status)) \
{ \
__R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
} \
return __status; \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
/// @endcond
//*****************************************************************************
// Macros for returning failures as NTSTATUS
//*****************************************************************************
// Always returns a known result (NTSTATUS) - always logs failures
#define NT_RETURN_NTSTATUS(status) __NT_RETURN_NTSTATUS(wil::verify_ntstatus(status), #status)
// Always returns a known failure (NTSTATUS) - always logs a var-arg message on failure
#define NT_RETURN_NTSTATUS_MSG(status, fmt, ...) \
__NT_RETURN_NTSTATUS_MSG(wil::verify_ntstatus(status), #status, fmt, ##__VA_ARGS__)
// Conditionally returns failures (NTSTATUS) - always logs failures
#define NT_RETURN_IF_NTSTATUS_FAILED(status) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
const auto __statusRet = wil::verify_ntstatus(status); \
if (FAILED_NTSTATUS(__statusRet)) \
{ \
__NT_RETURN_NTSTATUS(__statusRet, #status); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
// Conditionally returns failures (NTSTATUS) - always logs a var-arg message on failure
#define NT_RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
const auto __statusRet = wil::verify_ntstatus(status); \
if (FAILED_NTSTATUS(__statusRet)) \
{ \
__NT_RETURN_NTSTATUS_MSG(__statusRet, #status, fmt, ##__VA_ARGS__); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
//*****************************************************************************
// Macros to catch and convert exceptions on failure
//*****************************************************************************
// Use these macros *within* a catch (...) block to handle exceptions
#define NT_RETURN_CAUGHT_EXCEPTION() return __R_FN(Nt_Return_CaughtException)(__R_INFO_ONLY(nullptr))
#define NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) \
return __R_FN(Nt_Return_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
// Use these macros in place of a catch block to handle exceptions
#define NT_CATCH_RETURN() \
catch (...) \
{ \
NT_RETURN_CAUGHT_EXCEPTION(); \
}
#define NT_CATCH_RETURN_MSG(fmt, ...) \
catch (...) \
{ \
NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
}
namespace wil
{
//*****************************************************************************
// Public Helpers that catch -- mostly only enabled when exceptions are enabled
//*****************************************************************************
// StatusFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally
// it re-throws and catches the exception to convert it to an NTSTATUS. If an exception is of an unrecognized type
// the function will fail fast.
//
// try
// {
// // Code
// }
// catch (...)
// {
// status = wil::StatusFromCaughtException();
// }
_Always_(_Post_satisfies_(return < 0)) __declspec(noinline) inline NTSTATUS StatusFromCaughtException() WI_NOEXCEPT
{
bool isNormalized = false;
NTSTATUS status = STATUS_SUCCESS;
if (details::g_pfnResultFromCaughtExceptionInternal)
{
status = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).status;
}
if (FAILED_NTSTATUS(status))
{
return status;
}
// Caller bug: an unknown exception was thrown
__WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions);
return wil::details::HrToNtStatus(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
}
/// @cond
namespace details
{
template <FailureType>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(
__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
template <FailureType>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList);
namespace __R_NS_NAME
{
#ifdef WIL_ENABLE_EXCEPTIONS
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
{
__R_FN_LOCALS;
return wil::details::ReportStatus_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
}
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtExceptionMsg)
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
{
va_list argList;
va_start(argList, formatString);
__R_FN_LOCALS;
return wil::details::ReportStatus_CaughtExceptionMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
}
#endif
} // namespace __R_NS_NAME
template <FailureType T>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported)
{
wchar_t message[2048];
message[0] = L'\0';
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status;
}
template <>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::FailFast>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
{
wchar_t message[2048];
message[0] = L'\0';
RESULT_NORETURN_RESULT(
ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
}
template <>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::Exception>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
{
wchar_t message[2048];
message[0] = L'\0';
RESULT_NORETURN_RESULT(
ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
}
template <FailureType T>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
{
// Pre-populate the buffer with our message, the exception message will be added to it...
wchar_t message[2048];
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status;
}
template <>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::FailFast>(
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
{
// Pre-populate the buffer with our message, the exception message will be added to it...
wchar_t message[2048];
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
.status);
}
template <>
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::Exception>(
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
{
// Pre-populate the buffer with our message, the exception message will be added to it...
wchar_t message[2048];
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
.status);
}
} // namespace details
/// @endcond
} // namespace wil
#endif // __WIL_NT_RESULTMACROS_INCLUDED

3323
d3d11.x/wil/registry.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

7709
d3d11.x/wil/resource.h Normal file

File diff suppressed because it is too large Load Diff

1293
d3d11.x/wil/result.h Normal file

File diff suppressed because it is too large Load Diff

7338
d3d11.x/wil/result_macros.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Error Handling Helpers: supporting file enabling the originating of errors to produce better crash dumps
// Note: When origination is enabled by including this file, origination is done as part of the RETURN_* and THROW_* macros.
// Before originating a new error we will observe whether there is already an error payload associated with the current thread. If
// there is, and the HRESULTs match, then a new error will not be originated. Otherwise we will overwrite it with a new
// origination. The ABI boundary for WinRT APIs will check the per-thread error information. The act of checking the error
// clears it, so there should be minimal risk of failing to originate distinct errors simply because the HRESULTs match.
//
// For THROW_ macros we will examine the thread-local error storage once per throw. So typically once, with additional calls if
// the exception is caught and re-thrown.
//
// For RETURN_ macros we will have to examine the thread-local error storage once per frame as the call stack unwinds. Because
// error conditions -should- be uncommon the performance impact of checking TLS should be minimal. The more expensive part is
// originating the error because it must capture the entire stack and some additional data.
#ifndef __WIL_RESULT_ORIGINATE_INCLUDED
#define __WIL_RESULT_ORIGINATE_INCLUDED
#include "result.h"
#include <OleAuto.h> // RestrictedErrorInfo uses BSTRs :(
#include <winstring.h>
#include "resource.h"
#include "com.h"
#include <roerrorapi.h>
namespace wil
{
/// @cond
namespace details
{
// Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame.
inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT
{
if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception))
{
bool shouldOriginate = true;
wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
{
// This thread already has an error origination payload. Don't originate again if it has the same HRESULT that we
// are observing right now.
wil::unique_bstr descriptionUnused;
HRESULT existingHr = failure.hr;
wil::unique_bstr restrictedDescriptionUnused;
wil::unique_bstr capabilitySidUnused;
if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(
&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)))
{
shouldOriginate = (failure.hr != existingHr);
}
}
if (shouldOriginate)
{
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
wil::unique_hmodule errorModule;
if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule))
{
auto pfn = details::GetProcAddress<decltype(&::RoOriginateErrorW)>(errorModule.get(), "RoOriginateErrorW");
if (pfn != nullptr)
{
pfn(failure.hr, 0, failure.pszMessage);
}
}
#else // DESKTOP | SYSTEM
::RoOriginateErrorW(failure.hr, 0, failure.pszMessage);
#endif // DESKTOP | SYSTEM
}
else if (restrictedErrorInformation)
{
// GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was
// already present, then we need to restore the error information for later observation.
SetRestrictedErrorInfo(restrictedErrorInformation.get());
}
}
}
// This method will check for the presence of stowed exception data on the current thread. If such data exists, and the
// HRESULT matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this
// situation will result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we
// just return and the calling method fails fast the same way it always has.
inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT
{
wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
{
wil::unique_bstr descriptionUnused;
HRESULT existingHr = failure.hr;
wil::unique_bstr restrictedDescriptionUnused;
wil::unique_bstr capabilitySidUnused;
if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(
&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) &&
(existingHr == failure.hr))
{
// GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for
// RoFailFastWithErrorContext so we must restore it via SetRestrictedErrorInfo first.
SetRestrictedErrorInfo(restrictedErrorInformation.get());
RoFailFastWithErrorContext(existingHr);
}
else
{
// The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing
// fast in this method, so it is available in the debugger just-in-case.
SetRestrictedErrorInfo(restrictedErrorInformation.get());
}
}
}
} // namespace details
/// @endcond
} // namespace wil
// Automatically call RoOriginateError upon error origination by including this file
WI_HEADER_INITIALIZATION_FUNCTION(ResultStowedExceptionInitialize, [] {
::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions);
::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback);
return 1;
})
#endif // __WIL_RESULT_ORIGINATE_INCLUDED

219
d3d11.x/wil/rpc_helpers.h Normal file
View File

@@ -0,0 +1,219 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Helpers for invoking RPC functions and translating structured exceptions to HRESULTs or C++ exceptions
#ifndef __WIL_RPC_HELPERS_INCLUDED
#define __WIL_RPC_HELPERS_INCLUDED
#include "result.h"
#include "resource.h"
#include "wistd_functional.h"
#include "wistd_type_traits.h"
namespace wil
{
/// @cond
namespace details
{
// This call-adapter template converts a void-returning 'wistd::invoke' into
// an HRESULT-returning 'wistd::invoke' that emits S_OK. It can be eliminated
// with 'if constexpr' when C++17 is in wide use.
template <typename TReturnType>
struct call_adapter
{
template <typename... TArgs>
static HRESULT call(TArgs&&... args)
{
return wistd::invoke(wistd::forward<TArgs>(args)...);
}
};
template <>
struct call_adapter<void>
{
template <typename... TArgs>
static HRESULT call(TArgs&&... args)
{
wistd::invoke(wistd::forward<TArgs>(args)...);
return S_OK;
}
};
// Some RPC exceptions are already HRESULTs. Others are in the regular Win32
// error space. If the incoming exception code isn't an HRESULT, wrap it.
constexpr HRESULT map_rpc_exception(DWORD code)
{
return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code);
}
} // namespace details
/// @endcond
/** Invokes an RPC method, mapping structured exceptions to HRESULTs
Failures encountered by the RPC infrastructure (such as server crashes, authentication
errors, client parameter issues, etc.) are emitted by raising a structured exception from
within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept,
RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual
flow control machinery to use.
Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates
the result of the _work_. HRESULTs returned by a successful completion of the _call_ are
returned as-is.
RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_
completes successfully.
For example, consider an RPC interface method defined in idl as:
~~~
HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state);
~~~
To call this method, use:
~~~
wil::unique_rpc_binding binding = // typically gotten elsewhere;
wil::unique_midl_ptr<KittenState> state;
HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put());
RETURN_IF_FAILED(hr);
~~~
*/
template <typename... TCall>
HRESULT invoke_rpc_nothrow(TCall&&... args) WI_NOEXCEPT
{
RpcTryExcept
{
// Note: this helper type can be removed with C++17 enabled via
// 'if constexpr(wistd::is_same_v<void, result_t>)'
using result_t = typename wistd::__invoke_of<TCall...>::type;
RETURN_IF_FAILED(details::call_adapter<result_t>::call(wistd::forward<TCall>(args)...));
return S_OK;
}
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
{
RETURN_HR(details::map_rpc_exception(RpcExceptionCode()));
}
RpcEndExcept
}
/** Invokes an RPC method, mapping structured exceptions to HRESULTs
Failures encountered by the RPC infrastructure (such as server crashes, authentication
errors, client parameter issues, etc.) are emitted by raising a structured exception from
within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept,
RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual
flow control machinery to use.
Some RPC methods return results (such as a state enumeration or other value) directly in
their signature. This adapter writes that result into a caller-provided object then
returns S_OK.
For example, consider an RPC interface method defined in idl as:
~~~
GUID GetKittenId([in, ref, string] const wchar_t* name);
~~~
To call this method, use:
~~~
wil::unique_rpc_binding binding = // typically gotten elsewhere;
GUID id;
HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy");
RETURN_IF_FAILED(hr);
~~~
*/
template <typename TResult, typename... TCall>
HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT
{
RpcTryExcept
{
result = wistd::invoke(wistd::forward<TCall>(args)...);
return S_OK;
}
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
{
RETURN_HR(details::map_rpc_exception(RpcExceptionCode()));
}
RpcEndExcept
}
/// @cond
namespace details
{
// Provides an adapter around calling the context-handle-close method on an
// RPC interface, which itself is an RPC call.
template <typename TStorage, typename close_fn_t, close_fn_t close_fn>
struct rpc_closer_t
{
static void Close(TStorage arg) WI_NOEXCEPT
{
LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg));
}
};
} // namespace details
/// @endcond
/** Manages explicit RPC context handles
Explicit RPC context handles are used in many RPC interfaces. Most interfaces with
context handles have an explicit `FooClose([in, out] CONTEXT*)` method that lets
the server close out the context handle. As the close method itself is an RPC call,
it can fail and raise a structured exception.
This type routes the context-handle-specific `Close` call through the `invoke_rpc_nothrow`
helper, ensuring correct cleanup and lifecycle management.
@code
// Assume the interface has two methods:
// HRESULT OpenFoo([in] handle_t binding, [out] FOO_CONTEXT*);
// HRESULT UseFoo([in] FOO_CONTEXT context;
// void CloseFoo([in, out] PFOO_CONTEXT);
using unique_foo_context = wil::unique_rpc_context_handle<FOO_CONTEXT, decltype(&CloseFoo), CloseFoo>;
unique_foo_context context;
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put()));
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get()));
context.reset();
@endcode
*/
template <typename TContext, typename close_fn_t, close_fn_t close_fn>
using unique_rpc_context_handle =
unique_any<TContext, decltype(&details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close), details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close>;
#ifdef WIL_ENABLE_EXCEPTIONS
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_
and those returned by the _method_ are mapped to HRESULTs and thrown inside a
wil::ResultException. Using the example RPC method provided above:
@code
wil::unique_midl_ptr<KittenState> state;
wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put());
// use 'state'
@endcode
*/
template <typename... TCall>
void invoke_rpc(TCall&&... args)
{
THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward<TCall>(args)...));
}
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the
_call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the
example RPC method provided above:
@code
GUID id = wil::invoke_rpc_result(GetKittenId, binding.get());
// use 'id'
@endcode
*/
template <typename... TCall>
auto invoke_rpc_result(TCall&&... args)
{
using result_t = typename wistd::__invoke_of<TCall...>::type;
result_t result{};
THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward<TCall>(args)...));
return result;
}
#endif
} // namespace wil
#endif

401
d3d11.x/wil/safecast.h Normal file
View File

@@ -0,0 +1,401 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Type independent wrappers around the various intsafe.h functions
#ifndef __WIL_SAFECAST_INCLUDED
#define __WIL_SAFECAST_INCLUDED
#include "result_macros.h"
#include <intsafe.h>
#include "wistd_config.h"
#include "wistd_type_traits.h"
namespace wil
{
/// @cond
namespace details
{
// Default error case for undefined conversions in intsafe.h
template <typename OldT, typename NewT>
constexpr wistd::nullptr_t intsafe_conversion = nullptr;
// is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known
// safe conversions can be handled by static_cast, this includes conversions between the same
// type, when the new type is larger than the old type but is not a signed to unsigned
// conversion, and when the two types are the same size and signed/unsigned. All other
// conversions will be assumed to be potentially unsafe, and the conversion must be handled
// by intsafe and checked.
template <typename NewT, typename OldT>
constexpr bool is_known_safe_static_cast_v =
(sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v<OldT> && wistd::is_unsigned_v<NewT>)) ||
(sizeof(NewT) == sizeof(OldT) &&
((wistd::is_signed_v<NewT> && wistd::is_signed_v<OldT>) || (wistd::is_unsigned_v<NewT> && wistd::is_unsigned_v<OldT>)));
// Helper template to determine that NewT and OldT are both integral types. The safe_cast
// operation only supports conversions between integral types.
template <typename NewT, typename OldT>
constexpr bool both_integral_v = wistd::is_integral<NewT>::value && wistd::is_integral<OldT>::value;
// Helper template to determine that the cast from OldT to NewT is going to sign extend the
// value. This is only true when the size of NewT is larger than OldT and OldT is signed.
template <typename NewT, typename OldT>
constexpr bool is_sign_extending_cast_v =
(sizeof(NewT) >= sizeof(OldT)) && both_integral_v<NewT, OldT> && wistd::is_signed_v<OldT>;
// Note on native wchar_t (__wchar_t):
// Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is
// typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of
// support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an
// unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and
// share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast
// to a native wchar_t.
// Intsafe does not have a defined conversion for native wchar_t
template <typename NewT, typename OldT>
constexpr bool neither_native_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
// Check to see if the cast is a conversion to native wchar_t
template <typename NewT, typename OldT>
constexpr bool is_cast_to_wchar_v = wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
// Check to see if the cast is a conversion from native wchar_t
template <typename NewT, typename OldT>
constexpr bool is_cast_from_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && wistd::is_same<OldT, __wchar_t>::value;
// Validate the conversion to be performed has a defined mapping to an intsafe conversion
template <typename NewT, typename OldT>
constexpr bool is_supported_intsafe_cast_v = intsafe_conversion<OldT, NewT> != nullptr;
// True when the conversion is between integral types and can be handled by static_cast
template <typename NewT, typename OldT>
constexpr bool is_supported_safe_static_cast_v = both_integral_v<NewT, OldT> && is_known_safe_static_cast_v<NewT, OldT>;
// True when the conversion is between integral types, does not involve native wchar, has
// a mapped intsafe conversion, and is unsafe.
template <typename NewT, typename OldT>
constexpr bool is_supported_unsafe_cast_no_wchar_v =
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && neither_native_wchar_v<NewT, OldT> &&
is_supported_intsafe_cast_v<NewT, OldT>;
// True when the conversion is between integral types, is a cast to native wchar_t, has
// a mapped intsafe conversion, and is unsafe.
template <typename NewT, typename OldT>
constexpr bool is_supported_unsafe_cast_to_wchar_v =
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && is_cast_to_wchar_v<NewT, OldT> &&
is_supported_intsafe_cast_v<unsigned short, OldT>;
// True when the conversion is between integral types, is a cast from native wchar_t, has
// a mapped intsafe conversion, and is unsafe.
template <typename NewT, typename OldT>
constexpr bool is_supported_unsafe_cast_from_wchar_v =
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && is_cast_from_wchar_v<NewT, OldT> &&
is_supported_intsafe_cast_v<NewT, unsigned short>;
// True when the conversion is supported and unsafe, and may or may not involve
// native wchar_t.
template <typename NewT, typename OldT>
constexpr bool is_supported_unsafe_cast_v =
is_supported_unsafe_cast_no_wchar_v<NewT, OldT> || is_supported_unsafe_cast_to_wchar_v<NewT, OldT> ||
is_supported_unsafe_cast_from_wchar_v<NewT, OldT>;
// True when T is any one of the primitive types that the variably sized types are defined as.
template <typename T>
constexpr bool is_potentially_variably_sized_type_v =
wistd::is_same<T, int>::value || wistd::is_same<T, unsigned int>::value || wistd::is_same<T, long>::value ||
wistd::is_same<T, unsigned long>::value || wistd::is_same<T, __int64>::value || wistd::is_same<T, unsigned __int64>::value;
// True when either type is potentially variably sized (e.g. size_t, ptrdiff_t)
template <typename OldT, typename NewT>
constexpr bool is_potentially_variably_sized_cast_v =
is_potentially_variably_sized_type_v<OldT> || is_potentially_variably_sized_type_v<NewT>;
// Mappings of all conversions defined in intsafe.h to intsafe_conversion
// Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve
// to the base types. The base types are used since they do not vary based on architecture.
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, char> = IntToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, short> = IntToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, char> = LongToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, int> = LongToInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, short> = LongToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, char> = ShortToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
template <>
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
} // namespace details
/// @endcond
// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
{
NewT newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
return newVar;
}
// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
{
NewT newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
return newVar;
}
// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
{
unsigned short newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
return static_cast<__wchar_t>(newVar);
}
// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
{
return static_cast<NewT>(var);
}
#ifdef WIL_ENABLE_EXCEPTIONS
// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
{
NewT newVar;
THROW_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
return newVar;
}
// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
{
NewT newVar;
THROW_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
return newVar;
}
// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
{
unsigned short newVar;
THROW_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
return static_cast<__wchar_t>(newVar);
}
// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
{
return static_cast<NewT>(var);
}
#endif
// This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_nothrow(const OldT /*var*/)
{
static_assert(!wistd::is_same_v<NewT, NewT>, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead");
}
// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_nothrow(const OldT var)
{
return static_cast<NewT>(var);
}
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<OldT, NewT>(var, newTResult);
}
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), newTResult);
}
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<OldT, unsigned short>(var, reinterpret_cast<unsigned short*>(newTResult));
}
// This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion
// does not involve a variably sized type, then the compilation will fail and say the single parameter version
// of safe_cast_nothrow should be used instead.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
static_assert(
details::is_potentially_variably_sized_cast_v<OldT, NewT>,
"This cast is always safe; use safe_cast_nothrow<T>(value) to avoid unnecessary error handling.");
*newTResult = static_cast<NewT>(var);
return S_OK;
}
// This conversion takes a signed integer value and grows it with the upper bits set to zero. This is
// useful when the resulting value is cast to a pointer type as it prevents the upper bits from being fill
// which would adjust the pointed-to address.
//
// For example:
// wil::safe_zero_extending_cast<ULONG_PTR>(-1)
// will return 0x00000000`FFFFFFFF on a 64-bit system.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_sign_extending_cast_v<NewT, OldT>, int> = 0>
NewT safe_zero_extending_cast(const OldT var)
{
// The first cast is to an unsigned type of the same size as the original. The second cast is to the
// larger type. Being an unsigned cast, the upper bits are zeroed out.
using unsigned_old_t = wistd::make_unsigned_t<OldT>;
return static_cast<NewT>(static_cast<unsigned_old_t>(var));
}
} // namespace wil
#endif // __WIL_SAFECAST_INCLUDED

233
d3d11.x/wil/stl.h Normal file
View File

@@ -0,0 +1,233 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Windows STL helpers: custom allocators for STL containers
#ifndef __WIL_STL_INCLUDED
#define __WIL_STL_INCLUDED
#include "common.h"
#include "resource.h"
#include <memory>
#include <string>
#include <vector>
#include <utility>
#if (__WI_LIBCPP_STD_VER >= 17) && WI_HAS_INCLUDE(<string_view>, 1) // Assume present if C++17
#include <string_view>
#endif
/// @cond
#ifndef WI_STL_FAIL_FAST_IF
#define WI_STL_FAIL_FAST_IF FAIL_FAST_IF
#endif
/// @endcond
#if defined(WIL_ENABLE_EXCEPTIONS)
namespace wil
{
/** Secure allocator for STL containers.
The `wil::secure_allocator` allocator calls `SecureZeroMemory` before deallocating
memory. This provides a mechanism for secure STL containers such as `wil::secure_vector`,
`wil::secure_string`, and `wil::secure_wstring`. */
template <typename T>
struct secure_allocator : public std::allocator<T>
{
template <typename Other>
struct rebind
{
using other = secure_allocator<Other>;
};
secure_allocator() : std::allocator<T>()
{
}
~secure_allocator() = default;
secure_allocator(const secure_allocator& a) : std::allocator<T>(a)
{
}
template <class U>
secure_allocator(const secure_allocator<U>& a) : std::allocator<T>(a)
{
}
T* allocate(size_t n)
{
return std::allocator<T>::allocate(n);
}
void deallocate(T* p, size_t n)
{
SecureZeroMemory(p, sizeof(T) * n);
std::allocator<T>::deallocate(p, n);
}
};
//! `wil::secure_vector` will be securely zeroed before deallocation.
template <typename Type>
using secure_vector = std::vector<Type, secure_allocator<Type>>;
//! `wil::secure_wstring` will be securely zeroed before deallocation.
using secure_wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>, wil::secure_allocator<wchar_t>>;
//! `wil::secure_string` will be securely zeroed before deallocation.
using secure_string = std::basic_string<char, std::char_traits<char>, wil::secure_allocator<char>>;
/// @cond
namespace details
{
template <>
struct string_maker<std::wstring>
{
HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT
try
{
m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0');
return S_OK;
}
catch (...)
{
return E_OUTOFMEMORY;
}
wchar_t* buffer()
{
return &m_value[0];
}
HRESULT trim_at_existing_null(size_t length)
{
m_value.erase(length);
return S_OK;
}
std::wstring release()
{
return std::wstring(std::move(m_value));
}
static PCWSTR get(const std::wstring& value)
{
return value.c_str();
}
private:
std::wstring m_value;
};
} // namespace details
/// @endcond
// str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
// This is the overload for std::wstring. Other overloads available in resource.h.
inline PCWSTR str_raw_ptr(const std::wstring& str)
{
return str.c_str();
}
#if __cpp_lib_string_view >= 201606L
/**
zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty).
* zstring_view can be used for storing string literals without "forgetting" the length or that it is nul-terminated.
* A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a nul-terminated
string_view as a plain string view.
* A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated.
*/
template <class TChar>
class basic_zstring_view : public std::basic_string_view<TChar>
{
using size_type = typename std::basic_string_view<TChar>::size_type;
public:
constexpr basic_zstring_view() noexcept = default;
constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default;
constexpr basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default;
constexpr basic_zstring_view(const TChar* pStringData, size_type stringLength) noexcept :
std::basic_string_view<TChar>(pStringData, stringLength)
{
if (pStringData[stringLength] != 0)
{
WI_STL_FAIL_FAST_IF(true);
}
}
template <size_t stringArrayLength>
constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept :
std::basic_string_view<TChar>(&stringArray[0], length_n(&stringArray[0], stringArrayLength))
{
}
// Construct from nul-terminated char ptr. To prevent this from overshadowing array construction,
// we disable this constructor if the value is an array (including string literal).
template <typename TPtr, std::enable_if_t<std::is_convertible<TPtr, const TChar*>::value && !std::is_array<TPtr>::value>* = nullptr>
constexpr basic_zstring_view(TPtr&& pStr) noexcept : std::basic_string_view<TChar>(std::forward<TPtr>(pStr))
{
}
constexpr basic_zstring_view(const std::basic_string<TChar>& str) noexcept :
std::basic_string_view<TChar>(&str[0], str.size())
{
}
// basic_string_view [] precondition won't let us read view[view.size()]; so we define our own.
WI_NODISCARD constexpr const TChar& operator[](size_type idx) const noexcept
{
WI_ASSERT(idx <= this->size() && this->data() != nullptr);
return this->data()[idx];
}
WI_NODISCARD constexpr const TChar* c_str() const noexcept
{
WI_ASSERT(this->data() == nullptr || this->data()[this->size()] == 0);
return this->data();
}
private:
// Bounds-checked version of char_traits::length, like strnlen. Requires that the input contains a null terminator.
static constexpr size_type length_n(_In_reads_opt_(buf_size) const TChar* str, size_type buf_size) noexcept
{
const std::basic_string_view<TChar> view(str, buf_size);
auto pos = view.find_first_of(TChar());
if (pos == view.npos)
{
WI_STL_FAIL_FAST_IF(true);
}
return pos;
}
// The following basic_string_view methods must not be allowed because they break the nul-termination.
using std::basic_string_view<TChar>::swap;
using std::basic_string_view<TChar>::remove_suffix;
};
using zstring_view = basic_zstring_view<char>;
using zwstring_view = basic_zstring_view<wchar_t>;
inline namespace literals
{
constexpr zstring_view operator""_zv(const char* str, std::size_t len) noexcept
{
return zstring_view(str, len);
}
constexpr zwstring_view operator""_zv(const wchar_t* str, std::size_t len) noexcept
{
return zwstring_view(str, len);
}
} // namespace literals
#endif // __cpp_lib_string_view >= 201606L
} // namespace wil
#endif // WIL_ENABLE_EXCEPTIONS
#endif // __WIL_STL_INCLUDED

712
d3d11.x/wil/token_helpers.h Normal file
View File

@@ -0,0 +1,712 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Helpers for using tokens and impersonation
#ifndef __WIL_TOKEN_HELPERS_INCLUDED
#define __WIL_TOKEN_HELPERS_INCLUDED
#ifdef _KERNEL_MODE
#error This header is not supported in kernel-mode.
#endif
#include "resource.h"
#include <new>
#include <lmcons.h> // for UNLEN and DNLEN
#include <processthreadsapi.h>
// for GetUserNameEx()
/// @cond
#ifndef SECURITY_WIN32
#define SECURITY_WIN32
#endif
/// @endcond
#include <Security.h>
namespace wil
{
/// @cond
namespace details
{
// Template specialization for TOKEN_INFORMATION_CLASS, add more mappings here as needed
// TODO: The mapping should be reversed to be MapTokenInfoClassToStruct since there may
// be an info class value that uses the same structure. That is the case for the file
// system information.
template <typename T>
struct MapTokenStructToInfoClass;
template <>
struct MapTokenStructToInfoClass<TOKEN_ACCESS_INFORMATION>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_APPCONTAINER_INFORMATION>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_DEFAULT_DACL>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_GROUPS_AND_PRIVILEGES>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_MANDATORY_LABEL>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_OWNER>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOwner;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_PRIMARY_GROUP>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_PRIVILEGES>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges;
static constexpr bool FixedSize = false;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_USER>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenUser;
static constexpr bool FixedSize = false;
};
// fixed size cases
template <>
struct MapTokenStructToInfoClass<TOKEN_ELEVATION_TYPE>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevationType;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_MANDATORY_POLICY>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_ORIGIN>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOrigin;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_SOURCE>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenSource;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_STATISTICS>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenStatistics;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_TYPE>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenType;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<SECURITY_IMPERSONATION_LEVEL>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel;
static constexpr bool FixedSize = true;
};
template <>
struct MapTokenStructToInfoClass<TOKEN_ELEVATION>
{
static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevation;
static constexpr bool FixedSize = true;
};
struct token_info_deleter
{
template <typename T>
void operator()(T* p) const
{
static_assert(wistd::is_trivially_destructible_v<T>, "do not use with nontrivial types");
::operator delete(p);
}
};
} // namespace details
/// @endcond
enum class OpenThreadTokenAs
{
Current,
Self
};
/** Open the active token.
Opens either the current thread token (if impersonating) or the current process token. Returns a token the caller
can use with methods like get_token_information<> below. By default, the token is opened for TOKEN_QUERY and as the
effective user.
Consider using GetCurrentThreadEffectiveToken() instead of this method when eventually calling get_token_information.
This method returns a real handle to the effective token, but GetCurrentThreadEffectiveToken() is a Pseudo-handle
and much easier to manage.
~~~~
wil::unique_handle theToken;
RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken));
~~~~
Callers who want more access to the token (such as to duplicate or modify the token) can pass
any mask of the token rights.
~~~~
wil::unique_handle theToken;
RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES));
~~~~
Services impersonating their clients may need to request that the active token is opened on the
behalf of the service process to perform certain operations. Opening a token for impersonation access
or privilege-adjustment are examples of uses.
~~~~
wil::unique_handle callerToken;
RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_IMPERSONATE, OpenThreadTokenAs::Self));
~~~~
@param tokenHandle Receives the token opened during the operation. Must be CloseHandle'd by the caller, or
(preferably) stored in a wil::unique_handle
@param access Bits from the TOKEN_* access mask which are passed to OpenThreadToken/OpenProcessToken
@param openAs Current to use current thread security context, or Self to use process security context.
*/
inline HRESULT open_current_access_token_nothrow(
_Out_ HANDLE* tokenHandle, unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current)
{
HRESULT hr =
(OpenThreadToken(GetCurrentThread(), access, (openAs == OpenThreadTokenAs::Self), tokenHandle)
? S_OK
: HRESULT_FROM_WIN32(::GetLastError()));
if (hr == HRESULT_FROM_WIN32(ERROR_NO_TOKEN))
{
hr = (OpenProcessToken(GetCurrentProcess(), access, tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError()));
}
return hr;
}
//! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead.
inline wil::unique_handle open_current_access_token_failfast(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current)
{
HANDLE rawTokenHandle;
FAIL_FAST_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs));
return wil::unique_handle(rawTokenHandle);
}
// Exception based function to open current thread/process access token and acquire pointer to it
#ifdef WIL_ENABLE_EXCEPTIONS
//! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead.
inline wil::unique_handle open_current_access_token(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current)
{
HANDLE rawTokenHandle;
THROW_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs));
return wil::unique_handle(rawTokenHandle);
}
#endif // WIL_ENABLE_EXCEPTIONS
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
// Returns tokenHandle or the effective thread token if tokenHandle is null.
// Note, this returns an token handle who's lifetime is managed independently
// and it may be a pseudo token, don't free it!
inline HANDLE GetCurrentThreadEffectiveTokenWithOverride(HANDLE tokenHandle)
{
return tokenHandle ? tokenHandle : GetCurrentThreadEffectiveToken();
}
/** Fetches information about a token.
See GetTokenInformation on MSDN for what this method can return. For variable sized structs the information
is returned to the caller as a wil::unique_tokeninfo_ptr<T> (like TOKEN_ORIGIN, TOKEN_USER, TOKEN_ELEVATION, etc.). For
fixed sized, the struct is returned directly.
The caller must have access to read the information from the provided token. This method works with both real
(e.g. OpenCurrentAccessToken) and pseudo (e.g. GetCurrentThreadToken) token handles.
@code
// Retrieve the TOKEN_USER structure for the current process
wil::unique_tokeninfo_ptr<TOKEN_USER> user;
RETURN_IF_FAILED(wil::get_token_information_nothrow(user, GetCurrentProcessToken()));
RETURN_IF_FAILED(ConsumeSid(user->User.Sid));
@endcode
Not specifying the token handle is the same as specifying 'nullptr' and retrieves information about the effective token.
@code
wil::unique_tokeninfo_ptr<TOKEN_PRIVILEGES> privileges;
RETURN_IF_FAILED(wil::get_token_information_nothrow(privileges));
for (auto const& privilege : wil::GetRange(privileges->Privileges, privileges->PrivilegeCount))
{
RETURN_IF_FAILED(ConsumePrivilege(privilege));
}
@endcode
@param tokenInfo Receives a pointer to a structure containing the results of GetTokenInformation for the requested
type. The type of `<T>` selects which TOKEN_INFORMATION_CLASS will be used.
@param tokenHandle Specifies which token will be queried. When nullptr, the thread's effective current token is used.
@return S_OK on success, a FAILED hresult containing the win32 error from querying the token otherwise.
*/
template <typename Q>
using unique_tokeninfo_ptr = wistd::unique_ptr<Q, details::token_info_deleter>;
template <typename T, wistd::enable_if_t<!details::MapTokenStructToInfoClass<T>::FixedSize>* = nullptr>
inline HRESULT get_token_information_nothrow(unique_tokeninfo_ptr<T>& tokenInfo, HANDLE tokenHandle = nullptr)
{
tokenInfo.reset();
tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle);
DWORD tokenInfoSize = 0;
const auto infoClass = details::MapTokenStructToInfoClass<T>::infoClass;
RETURN_LAST_ERROR_IF(
!((!GetTokenInformation(tokenHandle, infoClass, nullptr, 0, &tokenInfoSize)) && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)));
unique_tokeninfo_ptr<T> tokenInfoClose{static_cast<T*>(::operator new(tokenInfoSize, std::nothrow))};
RETURN_IF_NULL_ALLOC(tokenInfoClose);
RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfoClose.get(), tokenInfoSize, &tokenInfoSize));
tokenInfo = wistd::move(tokenInfoClose);
return S_OK;
}
template <typename T, wistd::enable_if_t<details::MapTokenStructToInfoClass<T>::FixedSize>* = nullptr>
inline HRESULT get_token_information_nothrow(_Out_ T* tokenInfo, HANDLE tokenHandle = nullptr)
{
*tokenInfo = {};
tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle);
DWORD tokenInfoSize = sizeof(T);
const auto infoClass = details::MapTokenStructToInfoClass<T>::infoClass;
RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfo, tokenInfoSize, &tokenInfoSize));
return S_OK;
}
/// @cond
namespace details
{
template <typename T, typename policy, wistd::enable_if_t<!details::MapTokenStructToInfoClass<T>::FixedSize>* = nullptr>
unique_tokeninfo_ptr<T> GetTokenInfoWrap(HANDLE token = nullptr)
{
unique_tokeninfo_ptr<T> temp;
policy::HResult(get_token_information_nothrow(temp, token));
return temp;
}
template <typename T, typename policy, wistd::enable_if_t<details::MapTokenStructToInfoClass<T>::FixedSize>* = nullptr>
T GetTokenInfoWrap(HANDLE token = nullptr)
{
T temp{};
policy::HResult(get_token_information_nothrow(&temp, token));
return temp;
}
} // namespace details
/// @endcond
//! A variant of get_token_information<T> that fails-fast on errors retrieving the token
template <typename T>
inline auto get_token_information_failfast(HANDLE token = nullptr)
{
return details::GetTokenInfoWrap<T, err_failfast_policy>(token);
}
//! Overload of GetTokenInformationNoThrow that retrieves a token linked from the provided token
inline HRESULT get_token_information_nothrow(unique_token_linked_token& tokenInfo, HANDLE tokenHandle = nullptr)
{
static_assert(sizeof(tokenInfo) == sizeof(TOKEN_LINKED_TOKEN), "confusing size mismatch");
tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle);
DWORD tokenInfoSize = 0;
RETURN_IF_WIN32_BOOL_FALSE(
::GetTokenInformation(tokenHandle, TokenLinkedToken, tokenInfo.reset_and_addressof(), sizeof(tokenInfo), &tokenInfoSize));
return S_OK;
}
/** Retrieves the linked-token information for a token.
Fails-fast if the link information cannot be retrieved.
~~~~
auto link = get_linked_token_information_failfast(GetCurrentThreadToken());
auto tokenUser = get_token_information<TOKEN_USER>(link.LinkedToken);
~~~~
@param token Specifies the token to query. Pass nullptr to use the current effective thread token
@return unique_token_linked_token containing a handle to the linked token
*/
inline unique_token_linked_token get_linked_token_information_failfast(HANDLE token = nullptr)
{
unique_token_linked_token tokenInfo;
FAIL_FAST_IF_FAILED(get_token_information_nothrow(tokenInfo, token));
return tokenInfo;
}
#ifdef WIL_ENABLE_EXCEPTIONS
/** Fetches information about a token.
See get_token_information_nothrow for full details.
@code
auto user = wil::get_token_information<TOKEN_USER>(GetCurrentProcessToken());
ConsumeSid(user->User.Sid);
@endcode
Pass 'nullptr' (or omit the parameter) as tokenHandle to retrieve information about the effective token.
@code
auto privs = wil::get_token_information<TOKEN_PRIVILEGES>(privileges);
for (auto& priv : wil::make_range(privs->Privileges, privs->Privilieges + privs->PrivilegeCount))
{
if (priv.Attributes & SE_PRIVILEGE_ENABLED)
{
// ...
}
}
@endcode
@return A pointer to a structure containing the results of GetTokenInformation for the requested type. The type of
`<T>` selects which TOKEN_INFORMATION_CLASS will be used.
@param token Specifies which token will be queried. When nullptr or not set, the thread's effective current token is used.
*/
template <typename T>
inline auto get_token_information(HANDLE token = nullptr)
{
return details::GetTokenInfoWrap<T, err_exception_policy>(token);
}
/** Retrieves the linked-token information for a token.
Throws an exception if the link information cannot be retrieved.
~~~~
auto link = get_linked_token_information(GetCurrentThreadToken());
auto tokenUser = get_token_information<TOKEN_USER>(link.LinkedToken);
~~~~
@param token Specifies the token to query. Pass nullptr to use the current effective thread token
@return unique_token_linked_token containing a handle to the linked token
*/
inline unique_token_linked_token get_linked_token_information(HANDLE token = nullptr)
{
unique_token_linked_token tokenInfo;
THROW_IF_FAILED(get_token_information_nothrow(tokenInfo, token));
return tokenInfo;
}
#endif
#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8
/// @cond
namespace details
{
inline void RevertImpersonateToken(_In_ _Post_ptr_invalid_ HANDLE oldToken)
{
FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken));
if (oldToken)
{
::CloseHandle(oldToken);
}
}
} // namespace details
/// @endcond
using unique_token_reverter =
wil::unique_any<HANDLE, decltype(&details::RevertImpersonateToken), details::RevertImpersonateToken, details::pointer_access_none, HANDLE, INT_PTR, -1, HANDLE>;
/** Temporarily impersonates a token on this thread.
This method sets a new token on a thread, restoring the current token when the returned object
is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services.
~~~~
HRESULT OpenFileAsSessionuser(PCWSTR filePath, DWORD session, _Out_ HANDLE* opened)
{
wil::unique_handle userToken;
RETURN_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken));
wil::unique_token_reverter reverter;
RETURN_IF_FAILED(wil::impersonate_token_nothrow(userToken.get(), reverter));
wil::unique_hfile userFile(::CreateFile(filePath, ...));
RETURN_LAST_ERROR_IF(!userFile && (::GetLastError() != ERROR_FILE_NOT_FOUND));
*opened = userFile.release();
return S_OK;
}
~~~~
@param token A token to impersonate, or 'nullptr' to run as the process identity.
@param reverter An RAII object that, on success, will revert the impersonation when it goes out of scope.
*/
inline HRESULT impersonate_token_nothrow(HANDLE token, unique_token_reverter& reverter)
{
wil::unique_handle currentToken;
// Get the token for the current thread. If there wasn't one, the reset will clear it as well
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &currentToken))
{
RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_NO_TOKEN);
}
// Update the current token
RETURN_IF_WIN32_BOOL_FALSE(::SetThreadToken(nullptr, token));
reverter.reset(currentToken.release()); // Ownership passed
return S_OK;
}
/** Temporarily clears any impersonation on this thread.
This method resets the current thread's token to nullptr, indicating that it is not impersonating
any user. Useful for elevating to whatever identity a service or higher-privilege process might
be capable of running under.
~~~~
HRESULT DeleteFileRetryAsSelf(PCWSTR filePath)
{
if (!::DeleteFile(filePath))
{
RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_ACCESS_DENIED);
wil::unique_token_reverter reverter;
RETURN_IF_FAILED(wil::run_as_self_nothrow(reverter));
RETURN_IF_FAILED(TakeOwnershipOfFile(filePath));
RETURN_IF_FAILED(GrantDeleteAccess(filePath));
RETURN_IF_WIN32_BOOL_FALSE(::DeleteFile(filePath));
}
return S_OK;
}
~~~~
*/
inline HRESULT run_as_self_nothrow(unique_token_reverter& reverter)
{
return impersonate_token_nothrow(nullptr, reverter);
}
inline unique_token_reverter impersonate_token_failfast(HANDLE token)
{
unique_token_reverter oldToken;
FAIL_FAST_IF_FAILED(impersonate_token_nothrow(token, oldToken));
return oldToken;
}
inline unique_token_reverter run_as_self_failfast()
{
return impersonate_token_failfast(nullptr);
}
#ifdef WIL_ENABLE_EXCEPTIONS
/** Temporarily impersonates a token on this thread.
This method sets a new token on a thread, restoring the current token when the returned object
is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services.
~~~~
wil::unique_hfile OpenFileAsSessionuser(_In_z_ const wchar_t* filePath, DWORD session)
{
wil::unique_handle userToken;
THROW_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken));
auto priorToken = wil::impersonate_token(userToken.get());
wil::unique_hfile userFile(::CreateFile(filePath, ...));
THROW_LAST_ERROR_IF(::GetLastError() != ERROR_FILE_NOT_FOUND);
return userFile;
}
~~~~
@param token A token to impersonate, or 'nullptr' to run as the process identity.
*/
inline unique_token_reverter impersonate_token(HANDLE token = nullptr)
{
unique_token_reverter oldToken;
THROW_IF_FAILED(impersonate_token_nothrow(token, oldToken));
return oldToken;
}
/** Temporarily clears any impersonation on this thread.
This method resets the current thread's token to nullptr, indicating that it is not impersonating
any user. Useful for elevating to whatever identity a service or higher-privilege process might
be capable of running under.
~~~~
void DeleteFileRetryAsSelf(_In_z_ const wchar_t* filePath)
{
if (!::DeleteFile(filePath) && (::GetLastError() == ERROR_ACCESS_DENIED))
{
auto priorToken = wil::run_as_self();
TakeOwnershipOfFile(filePath);
GrantDeleteAccess(filePath);
::DeleteFile(filePath);
}
}
~~~~
*/
inline unique_token_reverter run_as_self()
{
return impersonate_token(nullptr);
}
#endif // WIL_ENABLE_EXCEPTIONS
/// @cond
namespace details
{
template <size_t AuthorityCount>
struct static_sid_t
{
BYTE Revision;
BYTE SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
DWORD SubAuthority[AuthorityCount];
PSID get()
{
return reinterpret_cast<PSID>(this);
}
template <size_t other>
static_sid_t& operator=(const static_sid_t<other>& source)
{
static_assert(other <= AuthorityCount, "Cannot assign from a larger static sid to a smaller one");
if (&this->Revision != &source.Revision)
{
memcpy(this, &source, sizeof(source));
}
return *this;
}
};
} // namespace details
/// @endcond
/** Returns a structure containing a Revision 1 SID initialized with the authorities provided
Replaces AllocateAndInitializeSid by constructing a structure laid out like a PSID, but
returned like a value. The resulting object is suitable for use with any method taking PSID,
passed by "&the_sid" or via "the_sid.get()"
@code
// Change the owner of the key to administrators
auto systemSid = wil::make_static_sid(SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
RETURN_IF_WIN32_ERROR(
SetNamedSecurityInfo(keyPath, SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION, &systemSid, nullptr, nullptr, nullptr));
@endcode
*/
template <typename... Ts>
constexpr auto make_static_sid(const SID_IDENTIFIER_AUTHORITY& authority, Ts&&... subAuthorities)
{
using sid_t = details::static_sid_t<sizeof...(subAuthorities)>;
static_assert(sizeof...(subAuthorities) <= SID_MAX_SUB_AUTHORITIES, "too many sub authorities");
static_assert(offsetof(sid_t, Revision) == offsetof(_SID, Revision), "layout mismatch");
static_assert(offsetof(sid_t, SubAuthorityCount) == offsetof(_SID, SubAuthorityCount), "layout mismatch");
static_assert(offsetof(sid_t, IdentifierAuthority) == offsetof(_SID, IdentifierAuthority), "layout mismatch");
static_assert(offsetof(sid_t, SubAuthority) == offsetof(_SID, SubAuthority), "layout mismatch");
return sid_t{SID_REVISION, sizeof...(subAuthorities), authority, {static_cast<DWORD>(subAuthorities)...}};
}
//! Variant of static_sid that defaults to the NT authority
template <typename... Ts>
constexpr auto make_static_nt_sid(Ts&&... subAuthorities)
{
return make_static_sid(SECURITY_NT_AUTHORITY, wistd::forward<Ts>(subAuthorities)...);
}
/** Determines whether a specified security identifier (SID) is enabled in an access token.
This function determines whether a security identifier, described by a given set of subauthorities, is enabled
in the given access token. Note that only up to eight subauthorities can be passed to this function.
~~~~
bool IsGuest()
{
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS));
}
~~~~
@param result This will be set to true if and only if a security identifier described by the given set of subauthorities is
enabled in the given access token.
@param token A handle to an access token. The handle must have TOKEN_QUERY access to the token, and must be an impersonation
token. If token is nullptr, test_token_membership uses the impersonation token of the calling thread. If the thread is not
impersonating, the function duplicates the thread's primary token to create an impersonation token.
@param sidAuthority A reference to a SID_IDENTIFIER_AUTHORITY structure. This structure provides the top-level identifier
authority value to set in the SID.
@param subAuthorities Up to 15 subauthority values to place in the SID (this is a systemwide limit)
@return S_OK on success, a FAILED hresult containing the win32 error from creating the SID or querying the token otherwise.
*/
template <typename... Ts>
HRESULT test_token_membership_nothrow(_Out_ bool* result, _In_opt_ HANDLE token, const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities)
{
*result = false;
auto tempSid = make_static_sid(sidAuthority, wistd::forward<Ts>(subAuthorities)...);
BOOL isMember;
RETURN_IF_WIN32_BOOL_FALSE(CheckTokenMembership(token, &tempSid, &isMember));
*result = (isMember != FALSE);
return S_OK;
}
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
/** Determine whether a token represents an app container
This method uses the passed in token and emits a boolean indicating that
whether TokenIsAppContainer is true.
~~~~
HRESULT OnlyIfAppContainer()
{
bool isAppContainer;
RETURN_IF_FAILED(wil::get_token_is_app_container_nothrow(nullptr, isAppContainer));
RETURN_HR_IF(E_ACCESSDENIED, !isAppContainer);
RETURN_HR(...);
}
~~~~
@param token A token to get info about, or 'nullptr' to run as the current thread.
@param value The result of the operation; `true` if the token represents an app container, `false` otherwise.
*/
inline HRESULT get_token_is_app_container_nothrow(_In_opt_ HANDLE token, bool& value)
{
DWORD isAppContainer = 0;
DWORD returnLength = 0;
RETURN_IF_WIN32_BOOL_FALSE(::GetTokenInformation(
token ? token : GetCurrentThreadEffectiveToken(), TokenIsAppContainer, &isAppContainer, sizeof(isAppContainer), &returnLength));
value = (isAppContainer != 0);
return S_OK;
}
//! A variant of get_token_is_app_container_nothrow that fails-fast on errors retrieving the token information
inline bool get_token_is_app_container_failfast(HANDLE token = nullptr)
{
bool value = false;
FAIL_FAST_IF_FAILED(get_token_is_app_container_nothrow(token, value));
return value;
}
#ifdef WIL_ENABLE_EXCEPTIONS
//! A variant of get_token_is_app_container_nothrow that throws on errors retrieving the token information
inline bool get_token_is_app_container(HANDLE token = nullptr)
{
bool value = false;
THROW_IF_FAILED(get_token_is_app_container_nothrow(token, value));
return value;
}
#endif // WIL_ENABLE_EXCEPTIONS
#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8
template <typename... Ts>
bool test_token_membership_failfast(_In_opt_ HANDLE token, const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities)
{
bool result;
FAIL_FAST_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward<Ts>(subAuthorities)...));
return result;
}
#ifdef WIL_ENABLE_EXCEPTIONS
template <typename... Ts>
bool test_token_membership(_In_opt_ HANDLE token, const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities)
{
bool result;
THROW_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward<Ts>(subAuthorities)...));
return result;
}
#endif
} // namespace wil
#endif // __WIL_TOKEN_HELPERS_INCLUDED

View File

@@ -0,0 +1,73 @@
#pragma once
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Various definitions for use in conjunction with TraceLogging APIs
#ifndef __WIL_TRACELOGGING_CONFIG_H
/// @cond
#define __WIL_TRACELOGGING_CONFIG_H
/// @endcond
// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition
// in this file configures the provider as a normal (non-telemetry) provider.
#define TraceLoggingOptionMicrosoftTelemetry() // Empty definition for TraceLoggingOptionMicrosoftTelemetry
// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition
// in this file configures the provider as a normal (non-telemetry) provider.
#define TraceLoggingOptionWindowsCoreTelemetry() // Empty definition for TraceLoggingOptionWindowsCoreTelemetry
// Event privacy tags. Use the PDT macro values for the tag parameter, e.g.:
// TraceLoggingWrite(...,
// TelemetryPrivacyDataTag(PDT_BrowsingHistory | PDT_ProductAndServiceUsage),
// ...);
#define TelemetryPrivacyDataTag(tag) TraceLoggingUInt64((tag), "PartA_PrivTags")
#define PDT_BrowsingHistory 0x0000000000000002u
#define PDT_DeviceConnectivityAndConfiguration 0x0000000000000800u
#define PDT_InkingTypingAndSpeechUtterance 0x0000000000020000u
#define PDT_ProductAndServicePerformance 0x0000000001000000u
#define PDT_ProductAndServiceUsage 0x0000000002000000u
#define PDT_SoftwareSetupAndInventory 0x0000000080000000u
// Event categories specified via keywords, e.g.:
// TraceLoggingWrite(...,
// TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
// ...);
#define MICROSOFT_KEYWORD_CRITICAL_DATA 0x0000800000000000 // Bit 47
#define MICROSOFT_KEYWORD_MEASURES 0x0000400000000000 // Bit 46
#define MICROSOFT_KEYWORD_TELEMETRY 0x0000200000000000 // Bit 45
#define MICROSOFT_KEYWORD_RESERVED_44 0x0000100000000000 // Bit 44 (reserved for future assignment)
// Event categories specified via event tags, e.g.:
// TraceLoggingWrite(...,
// TraceLoggingEventTag(MICROSOFT_EVENTTAG_REALTIME_LATENCY),
// ...);
#define MICROSOFT_EVENTTAG_DROP_USER_IDS 0x00008000
#define MICROSOFT_EVENTTAG_AGGREGATE 0x00010000
#define MICROSOFT_EVENTTAG_DROP_PII_EXCEPT_IP 0x00020000
#define MICROSOFT_EVENTTAG_COSTDEFERRED_LATENCY 0x00040000
#define MICROSOFT_EVENTTAG_CORE_DATA 0x00080000
#define MICROSOFT_EVENTTAG_INJECT_XTOKEN 0x00100000
#define MICROSOFT_EVENTTAG_REALTIME_LATENCY 0x00200000
#define MICROSOFT_EVENTTAG_NORMAL_LATENCY 0x00400000
#define MICROSOFT_EVENTTAG_CRITICAL_PERSISTENCE 0x00800000
#define MICROSOFT_EVENTTAG_NORMAL_PERSISTENCE 0x01000000
#define MICROSOFT_EVENTTAG_DROP_PII 0x02000000
#define MICROSOFT_EVENTTAG_HASH_PII 0x04000000
#define MICROSOFT_EVENTTAG_MARK_PII 0x08000000
// Field categories specified via field tags, e.g.:
// TraceLoggingWrite(...,
// TraceLoggingString(szUser, "UserName", "User's name", MICROSOFT_FIELDTAG_HASH_PII),
// ...);
#define MICROSOFT_FIELDTAG_DROP_PII 0x04000000
#define MICROSOFT_FIELDTAG_HASH_PII 0x08000000
#endif // __WIL_TRACELOGGING_CONFIG_H

1142
d3d11.x/wil/win32_helpers.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,205 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Error Handling Helpers: supporting file defining a family of macros and functions designed to uniformly handle errors
//! across return codes, fail fast, exceptions and logging for Win32 error codes.
#ifndef __WIL_WIN32_RESULTMACROS_INCLUDED
#define __WIL_WIN32_RESULTMACROS_INCLUDED
#include "result_macros.h"
// Helpers for return macros
/// @cond
#define __WIN32_RETURN_WIN32(error, str) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
const auto __error = (error); \
if (FAILED_WIN32(__error)) \
{ \
__R_FN(Return_Win32)(__R_INFO(str) __error); \
} \
return __error; \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define __WIN32_RETURN_GLE_FAIL(str) return __R_FN(Win32_Return_GetLastError)(__R_INFO_ONLY(str))
FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr)
{
if (SUCCEEDED(hr))
{
return ERROR_SUCCESS;
}
return HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr;
}
/// @endcond
//*****************************************************************************
// Macros for returning failures as WIN32 error codes
//*****************************************************************************
// Always returns a known result (WIN32 error code) - always logs failures
#define WIN32_RETURN_WIN32(error) __WIN32_RETURN_WIN32(wil::verify_win32(error), #error)
#define WIN32_RETURN_LAST_ERROR() __WIN32_RETURN_GLE_FAIL(nullptr)
// Conditionally returns failures (WIN32 error code) - always logs failures
#define WIN32_RETURN_IF_WIN32_ERROR(error) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
const auto __errorRet = wil::verify_win32(error); \
if (FAILED_WIN32(__errorRet)) \
{ \
__WIN32_RETURN_WIN32(__errorRet, #error); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_WIN32_IF(error, condition) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if (wil::verify_bool(condition)) \
{ \
__WIN32_RETURN_WIN32(wil::verify_win32(error), #condition); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_WIN32_IF_NULL(error, ptr) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if ((ptr) == nullptr) \
{ \
__WIN32_RETURN_WIN32(wil::verify_win32(error), #ptr); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_LAST_ERROR_IF(condition) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if (wil::verify_bool(condition)) \
{ \
__WIN32_RETURN_GLE_FAIL(#condition); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_LAST_ERROR_IF_NULL(ptr) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if ((ptr) == nullptr) \
{ \
__WIN32_RETURN_GLE_FAIL(#ptr); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
// Conditionally returns failures (WIN32 error code) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern
#define WIN32_RETURN_IF_WIN32_ERROR_EXPECTED(error) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
const auto __errorRet = wil::verify_win32(error); \
if (FAILED_WIN32(__errorRet)) \
{ \
return __errorRet; \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_WIN32_IF_EXPECTED(error, condition) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if (wil::verify_bool(condition)) \
{ \
return wil::verify_win32(error); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_WIN32_IF_NULL_EXPECTED(error, ptr) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if ((ptr) == nullptr) \
{ \
return wil::verify_win32(error); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_LAST_ERROR_IF_EXPECTED(condition) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if (wil::verify_bool(condition)) \
{ \
return wil::verify_win32(wil::details::GetLastErrorFail()); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
#define WIN32_RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) \
__WI_SUPPRESS_BREAKING_WARNINGS_S do \
{ \
if ((ptr) == nullptr) \
{ \
return wil::verify_win32(wil::details::GetLastErrorFail()); \
} \
} \
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
//*****************************************************************************
// Macros to catch and convert exceptions on failure
//*****************************************************************************
// Use these macros *within* a catch (...) block to handle exceptions
#define WIN32_RETURN_CAUGHT_EXCEPTION() return __R_FN(Win32_Return_CaughtException)(__R_INFO_ONLY(nullptr))
// Use these macros in place of a catch block to handle exceptions
#define WIN32_CATCH_RETURN() \
catch (...) \
{ \
WIN32_RETURN_CAUGHT_EXCEPTION(); \
}
namespace wil
{
//*****************************************************************************
// Public Helpers that catch -- mostly only enabled when exceptions are enabled
//*****************************************************************************
// Win32ErrorFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally
// it re-throws and catches the exception to convert it to a WIN32 error code. If an exception is of an unrecognized type
// the function will fail fast.
//
// try
// {
// // Code
// }
// catch (...)
// {
// status = wil::Win32ErrorFromCaughtException();
// }
_Always_(_Post_satisfies_(return > 0)) __declspec(noinline) inline long Win32ErrorFromCaughtException() WI_NOEXCEPT
{
return __WIN32_FROM_HRESULT(ResultFromCaughtException());
}
/// @cond
namespace details::__R_NS_NAME
{
#ifdef WIL_ENABLE_EXCEPTIONS
__R_DIRECT_METHOD(long, Win32_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
{
__R_FN_LOCALS;
return __WIN32_FROM_HRESULT(wil::details::ReportFailure_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
}
#endif
__R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
{
__R_FN_LOCALS;
return __WIN32_FROM_HRESULT(wil::details::ReportFailure_GetLastErrorHr<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
}
} // namespace details::__R_NS_NAME
/// @endcond
} // namespace wil
#endif // __WIL_WIN32_RESULTMACROS_INCLUDED

175
d3d11.x/wil/windowing.h Normal file
View File

@@ -0,0 +1,175 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
#ifndef __WIL_WINDOWING_INCLUDED
#define __WIL_WINDOWING_INCLUDED
#include <WinUser.h>
#include <exception>
#include "common.h"
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
namespace wil
{
namespace details
{
template <typename T>
struct always_false : wistd::false_type
{
};
template <typename TCallback>
BOOL __stdcall EnumWindowsCallbackNoThrow(HWND hwnd, LPARAM lParam)
{
auto pCallback = reinterpret_cast<TCallback*>(lParam);
#if __cpp_if_constexpr >= 201606L
using result_t = decltype((*pCallback)(hwnd));
if constexpr (wistd::is_void_v<result_t>)
{
(*pCallback)(hwnd);
return TRUE;
}
else if constexpr (wistd::is_same_v<result_t, HRESULT>)
{
// NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0
return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE;
}
else if constexpr (std::is_same_v<result_t, bool>)
{
return (*pCallback)(hwnd) ? TRUE : FALSE;
}
else
{
static_assert(details::always_false<TCallback>::value, "Callback must return void, bool, or HRESULT");
}
#else
return (*pCallback)(hwnd);
#endif
}
template <typename TEnumApi, typename TCallback>
void DoEnumWindowsNoThrow(TEnumApi&& enumApi, TCallback&& callback) noexcept
{
enumApi(EnumWindowsCallbackNoThrow<TCallback>, reinterpret_cast<LPARAM>(&callback));
}
#ifdef WIL_ENABLE_EXCEPTIONS
template <typename TCallback>
struct EnumWindowsCallbackData
{
std::exception_ptr exception;
TCallback* pCallback;
};
template <typename TCallback>
BOOL __stdcall EnumWindowsCallback(HWND hwnd, LPARAM lParam)
{
auto pCallbackData = reinterpret_cast<EnumWindowsCallbackData<TCallback>*>(lParam);
try
{
auto pCallback = pCallbackData->pCallback;
#if __cpp_if_constexpr >= 201606L
using result_t = decltype((*pCallback)(hwnd));
if constexpr (std::is_void_v<result_t>)
{
(*pCallback)(hwnd);
return TRUE;
}
else if constexpr (std::is_same_v<result_t, HRESULT>)
{
// NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0
return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE;
}
else if constexpr (std::is_same_v<result_t, bool>)
{
return (*pCallback)(hwnd) ? TRUE : FALSE;
}
else
{
static_assert(details::always_false<TCallback>::value, "Callback must return void, bool, or HRESULT");
}
#else
return (*pCallback)(hwnd);
#endif
}
catch (...)
{
pCallbackData->exception = std::current_exception();
return FALSE;
}
};
template <typename TEnumApi, typename TCallback>
void DoEnumWindows(TEnumApi&& enumApi, TCallback&& callback)
{
EnumWindowsCallbackData<TCallback> callbackData = {nullptr, &callback};
enumApi(EnumWindowsCallback<TCallback>, reinterpret_cast<LPARAM>(&callbackData));
if (callbackData.exception)
{
std::rethrow_exception(callbackData.exception);
}
}
#endif
} // namespace details
template <typename TCallback>
void for_each_window_nothrow(TCallback&& callback) noexcept
{
details::DoEnumWindowsNoThrow(&EnumWindows, wistd::forward<TCallback>(callback));
}
template <typename TCallback>
void for_each_thread_window_nothrow(_In_ DWORD threadId, TCallback&& callback) noexcept
{
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
return EnumThreadWindows(threadId, enumproc, lParam);
};
details::DoEnumWindowsNoThrow(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
}
template <typename TCallback>
void for_each_child_window_nothrow(_In_ HWND hwndParent, TCallback&& callback) noexcept
{
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
return EnumChildWindows(hwndParent, enumproc, lParam);
};
details::DoEnumWindowsNoThrow(boundEnumChildWindows, wistd::forward<TCallback>(callback));
}
#ifdef WIL_ENABLE_EXCEPTIONS
template <typename TCallback>
void for_each_window(TCallback&& callback)
{
details::DoEnumWindows(&EnumWindows, wistd::forward<TCallback>(callback));
}
template <typename TCallback>
void for_each_thread_window(_In_ DWORD threadId, TCallback&& callback)
{
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
return EnumThreadWindows(threadId, enumproc, lParam);
};
details::DoEnumWindows(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
}
template <typename TCallback>
void for_each_child_window(_In_ HWND hwndParent, TCallback&& callback)
{
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
return EnumChildWindows(hwndParent, enumproc, lParam);
};
details::DoEnumWindows(boundEnumChildWindows, wistd::forward<TCallback>(callback));
}
#endif
} // namespace wil
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#endif // __WIL_WINDOWING_INCLUDED

2502
d3d11.x/wil/winrt.h Normal file

File diff suppressed because it is too large Load Diff

586
d3d11.x/wil/wistd_config.h Normal file
View File

@@ -0,0 +1,586 @@
// -*- C++ -*-
//===--------------------------- __config ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// STL common functionality
//
// Some aspects of STL are core language concepts that should be used from all C++ code, regardless
// of whether exceptions are enabled in the component. Common library code that expects to be used
// from exception-free components want these concepts, but including STL headers directly introduces
// friction as it requires components not using STL to declare their STL version. Doing so creates
// ambiguity around whether STL use is safe in a particular component and implicitly brings in
// a long list of headers (including <new>) which can create further ambiguity around throwing new
// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has
// the potential to create naming conflicts or other implied dependencies.
//
// To promote the use of these core language concepts outside of STL-based binaries, this file is
// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding
// "std::" namespace STL functions and types should be preferred over these in code that is bound to
// STL. The implementation and naming of all functions are taken directly from STL, instead using
// "wistd" (Windows Implementation std) as the namespace.
//
// Routines in this namespace should always be considered a reflection of the *current* STL implementation
// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here.
//
// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation.
// Only code that is not exception-based and libraries that expect to be utilized across both exception
// and non-exception based code should utilize this functionality.
// This header mimics libc++'s '__config' header to the extent necessary to get the wistd::* definitions compiling. Note
// that this has a few key differences since libc++'s MSVC compatibility is currently not functional and a bit behind
#ifndef _WISTD_CONFIG_H_
#define _WISTD_CONFIG_H_
// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
#include <cstddef> // For size_t and other necessary types
/// @cond
#if defined(_MSC_VER) && !defined(__clang__)
#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#define __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
#endif
#endif
#ifndef __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
#pragma GCC system_header
#endif
#ifdef __GNUC__
#define __WI_GNUC_VER (__GNUC__ * 100 + __GNUC_MINOR__)
// The __WI_GNUC_VER_NEW macro better represents the new GCC versioning scheme
// introduced in GCC 5.0.
#define __WI_GNUC_VER_NEW (__WI_GNUC_VER * 10 + __GNUC_PATCHLEVEL__)
#else
#define __WI_GNUC_VER 0
#define __WI_GNUC_VER_NEW 0
#endif
// _MSVC_LANG is the more accurate way to get the C++ version in MSVC
#if defined(_MSVC_LANG) && (_MSVC_LANG > __cplusplus)
#define __WI_CPLUSPLUS _MSVC_LANG
#else
#define __WI_CPLUSPLUS __cplusplus
#endif
#ifndef __WI_LIBCPP_STD_VER
#if __WI_CPLUSPLUS <= 201103L
#define __WI_LIBCPP_STD_VER 11
#elif __WI_CPLUSPLUS <= 201402L
#define __WI_LIBCPP_STD_VER 14
#elif __WI_CPLUSPLUS <= 201703L
#define __WI_LIBCPP_STD_VER 17
#elif __WI_CPLUSPLUS <= 202002L
#define __WI_LIBCPP_STD_VER 20
#elif __WI_CPLUSPLUS <= 202302L
#define __WI_LIBCPP_STD_VER 23
#else
#define __WI_LIBCPP_STD_VER 24 // Newer standard or prerelease standard
#endif
#endif // __WI_LIBCPP_STD_VER
#if __WI_CPLUSPLUS < 201103L
#define __WI_LIBCPP_CXX03_LANG
#endif
#if defined(__ELF__)
#define __WI_LIBCPP_OBJECT_FORMAT_ELF 1
#elif defined(__MACH__)
#define __WI_LIBCPP_OBJECT_FORMAT_MACHO 1
#elif defined(_WIN32)
#define __WI_LIBCPP_OBJECT_FORMAT_COFF 1
#elif defined(__wasm__)
#define __WI_LIBCPP_OBJECT_FORMAT_WASM 1
#else
#error Unknown object file format
#endif
#if defined(__clang__)
#define __WI_LIBCPP_COMPILER_CLANG
#elif defined(__GNUC__)
#define __WI_LIBCPP_COMPILER_GCC
#elif defined(_MSC_VER)
#define __WI_LIBCPP_COMPILER_MSVC
#elif defined(__IBMCPP__)
#define __WI_LIBCPP_COMPILER_IBM
#endif
#if defined(__WI_LIBCPP_COMPILER_MSVC)
#define __WI_PUSH_WARNINGS __pragma(warning(push))
#define __WI_POP_WARNINGS __pragma(warning(pop))
#elif defined(__WI_LIBCPP_COMPILER_CLANG)
#define __WI_PUSH_WARNINGS __pragma(clang diagnostic push)
#define __WI_POP_WARNINGS __pragma(clang diagnostic pop)
#else
#define __WI_PUSH_WARNINGS
#define __WI_POP_WARNINGS
#endif
#ifdef __WI_LIBCPP_COMPILER_MSVC
#define __WI_MSVC_DISABLE_WARNING(id) __pragma(warning(disable : id))
#else
#define __WI_MSVC_DISABLE_WARNING(id)
#endif
#ifdef __WI_LIBCPP_COMPILER_CLANG
#define __WI_CLANG_DISABLE_WARNING(warning) __pragma(clang diagnostic ignored #warning)
#else
#define __WI_CLANG_DISABLE_WARNING(warning)
#endif
// NOTE: MSVC, which is what we primarily target, is severely underrepresented in libc++ and checks such as
// __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we
// instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls
// back to the __has_feature(...), etc. value otherwise. We intentionally leave '__has_feature', etc. undefined for MSVC
// so that we don't accidentally use the incorrect behavior
#ifndef __WI_LIBCPP_COMPILER_MSVC
#ifndef __has_feature
#define __has_feature(__x) 0
#endif
// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
// the compiler and '1' otherwise.
#ifndef __is_identifier
#define __is_identifier(__x) 1
#endif
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(__x) 0
#endif
#ifndef __has_attribute
#define __has_attribute(__x) 0
#endif
#ifndef __has_builtin
#define __has_builtin(__x) 0
#endif
#if __has_feature(cxx_alignas)
#define __WI_ALIGNAS_TYPE(x) alignas(x)
#define __WI_ALIGNAS(x) alignas(x)
#else
#define __WI_ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x))))
#define __WI_ALIGNAS(x) __attribute__((__aligned__(x)))
#endif
#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \
(!defined(__WI_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions
#define __WI_LIBCPP_EXPLICIT explicit
#else
#define __WI_LIBCPP_EXPLICIT
#endif
#if __has_feature(cxx_attributes)
#define __WI_LIBCPP_NORETURN [[noreturn]]
#else
#define __WI_LIBCPP_NORETURN __attribute__((noreturn))
#endif
#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS
// The __WI_LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other
// NODISCARD macros to the correct attribute.
#if __has_cpp_attribute(nodiscard)
#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]]
#elif defined(__WI_LIBCPP_COMPILER_CLANG) && !defined(__WI_LIBCPP_CXX03_LANG)
#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]]
#else
// We can't use GCC's [[gnu::warn_unused_result]] and
// __attribute__((warn_unused_result)), because GCC does not silence them via
// (void) cast.
#define __WI_LIBCPP_NODISCARD_ATTRIBUTE
#endif
#define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union)
#define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class)
#define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum)
#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to)
#define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty)
#define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic)
#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor)
#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS __has_feature(cxx_reference_qualified_functions)
#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE __has_feature(is_constructible)
#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE __has_feature(is_trivially_constructible)
#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE __has_feature(is_trivially_assignable)
#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR __has_feature(has_trivial_destructor)
#define __WI_HAS_FEATURE_NOEXCEPT __has_feature(cxx_noexcept)
#define __WI_HAS_FEATURE_IS_POD __has_feature(is_pod)
#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT __has_feature(is_standard_layout)
#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE __has_feature(is_trivially_copyable)
#define __WI_HAS_FEATURE_IS_TRIVIAL __has_feature(is_trivial)
#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR __has_feature(has_trivial_constructor) || (__WI_GNUC_VER >= 403)
#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR __has_feature(has_nothrow_constructor) || (__WI_GNUC_VER >= 403)
#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403)
#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403)
#if !(__has_feature(cxx_noexcept))
#define __WI_LIBCPP_HAS_NO_NOEXCEPT
#endif
#if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700
#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS
#endif
#if !(__has_feature(cxx_variadic_templates))
#define __WI_LIBCPP_HAS_NO_VARIADICS
#endif
#if __has_feature(is_literal) || __WI_GNUC_VER >= 407
#define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T)
#endif
#if __has_feature(underlying_type) || __WI_GNUC_VER >= 407
#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T)
#endif
#if __has_feature(is_final) || __WI_GNUC_VER >= 407
#define __WI_LIBCPP_HAS_IS_FINAL
#endif
#if __has_feature(is_base_of) || defined(__GNUC__) && __WI_GNUC_VER >= 403
#define __WI_LIBCPP_HAS_IS_BASE_OF
#endif
#if __is_identifier(__is_aggregate) && (__WI_GNUC_VER_NEW < 7001)
#define __WI_LIBCPP_HAS_NO_IS_AGGREGATE
#endif
#if !(__has_feature(cxx_rtti)) && !defined(__WI_LIBCPP_NO_RTTI)
#define __WI_LIBCPP_NO_RTTI
#endif
#if !(__has_feature(cxx_variable_templates))
#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
#endif
#if !(__has_feature(cxx_relaxed_constexpr))
#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR
#endif
#if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700
#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
#endif
#if __has_attribute(__no_sanitize__) && !defined(__WI_LIBCPP_COMPILER_GCC)
#define __WI_LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi")))
#else
#define __WI_LIBCPP_NO_CFI
#endif
#define __WI_LIBCPP_ALWAYS_INLINE __attribute__((__always_inline__))
#if __has_attribute(internal_linkage)
#define __WI_LIBCPP_INTERNAL_LINKAGE __attribute__((internal_linkage))
#else
#define __WI_LIBCPP_INTERNAL_LINKAGE __WI_LIBCPP_ALWAYS_INLINE
#endif
#else
// NOTE: Much of the following assumes a decently recent version of MSVC. Past versions can be supported, but will need
// to be updated to contain the proper _MSC_VER check
#define __WI_ALIGNAS_TYPE(x) alignas(x)
#define __WI_ALIGNAS(x) alignas(x)
#define __alignof__ __alignof
#define __WI_LIBCPP_EXPLICIT explicit
#define __WI_LIBCPP_NORETURN [[noreturn]]
#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress : 26495))
#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress : 26439))
#if __WI_LIBCPP_STD_VER > 14
#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]]
#else
#define __WI_LIBCPP_NODISCARD_ATTRIBUTE _Check_return_
#endif
#define __WI_HAS_FEATURE_IS_UNION 1
#define __WI_HAS_FEATURE_IS_CLASS 1
#define __WI_HAS_FEATURE_IS_ENUM 1
#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 1
#define __WI_HAS_FEATURE_IS_EMPTY 1
#define __WI_HAS_FEATURE_IS_POLYMORPHIC 1
#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR 1
#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1
#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS 1
#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE 1
#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE 1
#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR 1
#define __WI_HAS_FEATURE_NOEXCEPT 1
#define __WI_HAS_FEATURE_IS_POD 1
#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT 1
#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE 1
#define __WI_HAS_FEATURE_IS_TRIVIAL 1
#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR 1
#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR 1
#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY 1
#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN 1
#define __WI_HAS_FEATURE_IS_DESTRUCTIBLE 1
#if !defined(_CPPRTTI) && !defined(__WI_LIBCPP_NO_RTTI)
#define __WI_LIBCPP_NO_RTTI
#endif
#define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T)
#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T)
#define __WI_LIBCPP_HAS_IS_FINAL
#define __WI_LIBCPP_HAS_IS_BASE_OF
#if __WI_LIBCPP_STD_VER < 14
#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
#endif
#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
#define __WI_LIBCPP_NO_CFI
#define __WI_LIBCPP_ALWAYS_INLINE __forceinline
#define __WI_LIBCPP_INTERNAL_LINKAGE
#endif
#ifndef _WIN32
#ifdef __LITTLE_ENDIAN__
#if __LITTLE_ENDIAN__
#define __WI_LIBCPP_LITTLE_ENDIAN
#endif // __LITTLE_ENDIAN__
#endif // __LITTLE_ENDIAN__
#ifdef __BIG_ENDIAN__
#if __BIG_ENDIAN__
#define __WI_LIBCPP_BIG_ENDIAN
#endif // __BIG_ENDIAN__
#endif // __BIG_ENDIAN__
#ifdef __BYTE_ORDER__
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __WI_LIBCPP_LITTLE_ENDIAN
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define __WI_LIBCPP_BIG_ENDIAN
#endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#endif // __BYTE_ORDER__
#if !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN)
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define __WI_LIBCPP_LITTLE_ENDIAN
#elif __BYTE_ORDER == __BIG_ENDIAN
#define __WI_LIBCPP_BIG_ENDIAN
#else // __BYTE_ORDER == __BIG_ENDIAN
#error unable to determine endian
#endif
#endif // !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN)
#else // _WIN32
#define __WI_LIBCPP_LITTLE_ENDIAN
#endif // _WIN32
#ifdef __WI_LIBCPP_HAS_NO_CONSTEXPR
#define __WI_LIBCPP_CONSTEXPR
#else
#define __WI_LIBCPP_CONSTEXPR constexpr
#endif
#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr
#else
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11
#endif
#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr
#else
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14
#endif
#if __WI_LIBCPP_STD_VER > 17 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr
#else
#define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17
#endif
#if !defined(__WI_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && (__WI_LIBCPP_STD_VER > 17 || defined(__WI_LIBCPP_ENABLE_NODISCARD))
#define __WI_LIBCPP_NODISCARD_AFTER_CXX17 __WI_LIBCPP_NODISCARD_ATTRIBUTE
#else
#define __WI_LIBCPP_NODISCARD_AFTER_CXX17
#endif
#if __WI_LIBCPP_STD_VER > 14 && defined(__cpp_inline_variables) && (__cpp_inline_variables >= 201606L)
#define __WI_LIBCPP_INLINE_VAR inline
#else
#define __WI_LIBCPP_INLINE_VAR
#endif
#ifdef __WI_LIBCPP_CXX03_LANG
#define __WI_LIBCPP_HAS_NO_UNICODE_CHARS
#define __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES
#endif
#ifndef __SIZEOF_INT128__
#define __WI_LIBCPP_HAS_NO_INT128
#endif
#if !__WI_HAS_FEATURE_NOEXCEPT && !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT)
#define __WI_LIBCPP_HAS_NO_NOEXCEPT
#endif
#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT
#define WI_NOEXCEPT noexcept
#define __WI_NOEXCEPT_(x) noexcept(x)
#else
#define WI_NOEXCEPT throw()
#define __WI_NOEXCEPT_(x)
#endif
#if defined(__WI_LIBCPP_OBJECT_FORMAT_COFF)
#define __WI_LIBCPP_HIDDEN
#define __WI_LIBCPP_TEMPLATE_VIS
#endif // defined(__WI_LIBCPP_OBJECT_FORMAT_COFF)
#ifndef __WI_LIBCPP_HIDDEN
#if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
#define __WI_LIBCPP_HIDDEN __attribute__((__visibility__("hidden")))
#else
#define __WI_LIBCPP_HIDDEN
#endif
#endif
#ifndef __WI_LIBCPP_TEMPLATE_VIS
#if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !defined(__WI_LIBCPP_COMPILER_MSVC)
#if __has_attribute(__type_visibility__)
#define __WI_LIBCPP_TEMPLATE_VIS __attribute__((__type_visibility__("default")))
#else
#define __WI_LIBCPP_TEMPLATE_VIS __attribute__((__visibility__("default")))
#endif
#else
#define __WI_LIBCPP_TEMPLATE_VIS
#endif
#endif
#define __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_HIDDEN __WI_LIBCPP_INTERNAL_LINKAGE
namespace wistd // ("Windows Implementation" std)
{
using nullptr_t = decltype(__nullptr);
template <class _T1, class _T2 = _T1>
struct __less
{
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T1& __x, const _T1& __y) const
{
return __x < __y;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T1& __x, const _T2& __y) const
{
return __x < __y;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T2& __x, const _T1& __y) const
{
return __x < __y;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T2& __x, const _T2& __y) const
{
return __x < __y;
}
};
template <class _T1>
struct __less<_T1, _T1>
{
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T1& __x, const _T1& __y) const
{
return __x < __y;
}
};
template <class _T1>
struct __less<const _T1, _T1>
{
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T1& __x, const _T1& __y) const
{
return __x < __y;
}
};
template <class _T1>
struct __less<_T1, const _T1>
{
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
const _T1& __x, const _T1& __y) const
{
return __x < __y;
}
};
// These are added to wistd to enable use of min/max without having to use the windows.h min/max
// macros that some clients might not have access to. Note: the STL versions of these have debug
// checking for the less than operator and support for iterators that these implementations lack.
// Use the STL versions when you require use of those features.
// min
template <class _Tp, class _Compare>
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(min)(const _Tp& __a, const _Tp& __b, _Compare __comp)
{
return __comp(__b, __a) ? __b : __a;
}
template <class _Tp>
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(min)(const _Tp& __a, const _Tp& __b)
{
return (min)(__a, __b, __less<_Tp>());
}
// max
template <class _Tp, class _Compare>
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(max)(const _Tp& __a, const _Tp& __b, _Compare __comp)
{
return __comp(__a, __b) ? __b : __a;
}
template <class _Tp>
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(max)(const _Tp& __a, const _Tp& __b)
{
return (max)(__a, __b, __less<_Tp>());
}
template <class _Arg, class _Result>
struct __WI_LIBCPP_TEMPLATE_VIS unary_function
{
using argument_type = _Arg;
using result_type = _Result;
};
template <class _Arg1, class _Arg2, class _Result>
struct __WI_LIBCPP_TEMPLATE_VIS binary_function
{
using first_argument_type = _Arg1;
using second_argument_type = _Arg2;
using result_type = _Result;
};
} // namespace wistd
/// @endcond
#endif // _WISTD_CONFIG_H_

View File

@@ -0,0 +1,568 @@
// -*- C++ -*-
//===------------------------ functional ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// STL common functionality
//
// Some aspects of STL are core language concepts that should be used from all C++ code, regardless
// of whether exceptions are enabled in the component. Common library code that expects to be used
// from exception-free components want these concepts, but including STL headers directly introduces
// friction as it requires components not using STL to declare their STL version. Doing so creates
// ambiguity around whether STL use is safe in a particular component and implicitly brings in
// a long list of headers (including <new>) which can create further ambiguity around throwing new
// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has
// the potential to create naming conflicts or other implied dependencies.
//
// To promote the use of these core language concepts outside of STL-based binaries, this file is
// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding
// "std::" namespace STL functions and types should be preferred over these in code that is bound to
// STL. The implementation and naming of all functions are taken directly from STL, instead using
// "wistd" (Windows Implementation std) as the namespace.
//
// Routines in this namespace should always be considered a reflection of the *current* STL implementation
// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here.
//
// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation.
// Only code that is not exception-based and libraries that expect to be utilized across both exception
// and non-exception based code should utilize this functionality.
#ifndef _WISTD_FUNCTIONAL_H_
#define _WISTD_FUNCTIONAL_H_
// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
#include "wistd_memory.h"
#include <intrin.h> // For __fastfail
#include <new.h> // For placement new
#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#pragma warning(push)
#pragma warning(disable : 4324)
#pragma warning(disable : 4800)
/// @cond
namespace wistd // ("Windows Implementation" std)
{
// wistd::function
//
// All of the code below is in direct support of wistd::function. This class is identical to std::function
// with the following exceptions:
//
// 1) It never allocates and is safe to use from exception-free code (custom allocators are not supported)
// 2) It's slightly bigger on the stack (64 bytes, rather than 24 for 32bit)
// 3) There is an explicit static-assert if a lambda becomes too large to hold in the internal buffer (rather than an allocation)
template <class _Ret>
struct __invoke_void_return_wrapper
{
#ifndef __WI_LIBCPP_CXX03_LANG
template <class... _Args>
static _Ret __call(_Args&&... __args)
{
return __invoke(wistd::forward<_Args>(__args)...);
}
#else
template <class _Fn>
static _Ret __call(_Fn __f)
{
return __invoke(__f);
}
template <class _Fn, class _A0>
static _Ret __call(_Fn __f, _A0& __a0)
{
return __invoke(__f, __a0);
}
template <class _Fn, class _A0, class _A1>
static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1)
{
return __invoke(__f, __a0, __a1);
}
template <class _Fn, class _A0, class _A1, class _A2>
static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2)
{
return __invoke(__f, __a0, __a1, __a2);
}
#endif
};
template <>
struct __invoke_void_return_wrapper<void>
{
#ifndef __WI_LIBCPP_CXX03_LANG
template <class... _Args>
static void __call(_Args&&... __args)
{
(void)__invoke(wistd::forward<_Args>(__args)...);
}
#else
template <class _Fn>
static void __call(_Fn __f)
{
__invoke(__f);
}
template <class _Fn, class _A0>
static void __call(_Fn __f, _A0& __a0)
{
__invoke(__f, __a0);
}
template <class _Fn, class _A0, class _A1>
static void __call(_Fn __f, _A0& __a0, _A1& __a1)
{
__invoke(__f, __a0, __a1);
}
template <class _Fn, class _A0, class _A1, class _A2>
static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2)
{
__invoke(__f, __a0, __a1, __a2);
}
#endif
};
////////////////////////////////////////////////////////////////////////////////
// FUNCTION
//==============================================================================
// bad_function_call
__WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY void __throw_bad_function_call()
{
__fastfail(7); // FAST_FAIL_FATAL_APP_EXIT
}
template <class _Fp>
class __WI_LIBCPP_TEMPLATE_VIS function; // undefined
namespace __function
{
template <class _Rp>
struct __maybe_derive_from_unary_function
{
};
template <class _Rp, class _A1>
struct __maybe_derive_from_unary_function<_Rp(_A1)> : public unary_function<_A1, _Rp>
{
};
template <class _Rp>
struct __maybe_derive_from_binary_function
{
};
template <class _Rp, class _A1, class _A2>
struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public binary_function<_A1, _A2, _Rp>
{
};
template <class _Fp>
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp const&)
{
return true;
}
template <class _Fp>
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp* __ptr)
{
return __ptr;
}
template <class _Ret, class _Class>
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Ret _Class::* __ptr)
{
return __ptr;
}
template <class _Fp>
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(function<_Fp> const& __f)
{
return !!__f;
}
} // namespace __function
#ifndef __WI_LIBCPP_CXX03_LANG
namespace __function
{
template <class _Fp>
class __base;
template <class _Rp, class... _ArgTypes>
class __base<_Rp(_ArgTypes...)>
{
__base(const __base&);
__base& operator=(const __base&);
public:
__WI_LIBCPP_INLINE_VISIBILITY __base()
{
}
__WI_LIBCPP_INLINE_VISIBILITY virtual ~__base()
{
}
virtual void __clone(__base*) const = 0;
virtual void __move(__base*) = 0;
virtual void destroy() WI_NOEXCEPT = 0;
virtual _Rp operator()(_ArgTypes&&...) = 0;
};
template <class _FD, class _FB>
class __func;
template <class _Fp, class _Rp, class... _ArgTypes>
class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)>
{
_Fp __f_;
public:
__WI_LIBCPP_INLINE_VISIBILITY
explicit __func(_Fp&& __f) : __f_(wistd::move(__f))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
explicit __func(const _Fp& __f) : __f_(__f)
{
}
virtual void __clone(__base<_Rp(_ArgTypes...)>*) const;
virtual void __move(__base<_Rp(_ArgTypes...)>*);
virtual void destroy() WI_NOEXCEPT;
virtual _Rp operator()(_ArgTypes&&... __arg);
};
template <class _Fp, class _Rp, class... _ArgTypes>
void __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const
{
::new (__p) __func(__f_);
}
template <class _Fp, class _Rp, class... _ArgTypes>
void __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p)
{
::new (__p) __func(wistd::move(__f_));
}
template <class _Fp, class _Rp, class... _ArgTypes>
void __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT
{
__f_.~_Fp();
}
template <class _Fp, class _Rp, class... _ArgTypes>
_Rp __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg)
{
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...);
}
// 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects
// that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12
// pointers (__base vtable takes an additional one).
constexpr const size_t __buffer_size = 13 * sizeof(void*);
} // namespace __function
// NOTE: The extra 'alignas' here is to work around the x86 compiler bug mentioned in
// https://github.com/microsoft/STL/issues/1533 to force alignment on the stack
template <class _Rp, class... _ArgTypes>
class __WI_LIBCPP_TEMPLATE_VIS __WI_ALIGNAS(typename aligned_storage<__function::__buffer_size>::type) function<_Rp(_ArgTypes...)>
: public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>,
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)>
{
using __base = __function::__base<_Rp(_ArgTypes...)>;
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
typename aligned_storage<__function::__buffer_size>::type __buf_;
__base* __f_;
__WI_LIBCPP_NO_CFI static __base* __as_base(void* p)
{
return static_cast<__base*>(p);
}
template <class _Fp, bool>
struct __callable_imp
{
static const bool value = is_same<void, _Rp>::value || is_convertible<typename __invoke_of<_Fp&, _ArgTypes...>::type, _Rp>::value;
};
template <class _Fp>
struct __callable_imp<_Fp, false>
{
static constexpr bool value = false;
};
template <class _Fp>
struct __callable
{
static const bool value =
__callable_imp<_Fp, __lazy_and<integral_constant<bool, !is_same<__uncvref_t<_Fp>, function>::value>, __invokable<_Fp&, _ArgTypes...>>::value>::value;
};
template <class _Fp>
using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type;
public:
using result_type = _Rp;
// construct/copy/destroy:
__WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function() WI_NOEXCEPT : __f_(0)
{
}
__WI_LIBCPP_INLINE_VISIBILITY
function(nullptr_t) WI_NOEXCEPT : __f_(0)
{
}
function(const function&);
function(function&&);
template <class _Fp, class = _EnableIfCallable<_Fp>>
function(_Fp);
function& operator=(const function&);
function& operator=(function&&);
function& operator=(nullptr_t) WI_NOEXCEPT;
template <class _Fp, class = _EnableIfCallable<_Fp>>
function& operator=(_Fp&&);
~function();
// function modifiers:
void swap(function&);
// function capacity:
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT
{
return __f_;
}
// deleted overloads close possible hole in the type system
template <class _R2, class... _ArgTypes2>
bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete;
template <class _R2, class... _ArgTypes2>
bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete;
public:
// function invocation:
_Rp operator()(_ArgTypes...) const;
// NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than
// 'std' so all functions requiring RTTI have been removed
};
template <class _Rp, class... _ArgTypes>
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(const function& __f)
{
if (__f.__f_ == nullptr)
__f_ = 0;
else
{
__f_ = __as_base(&__buf_);
__f.__f_->__clone(__f_);
}
}
template <class _Rp, class... _ArgTypes>
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS function<_Rp(_ArgTypes...)>::function(function&& __f)
{
if (__f.__f_ == nullptr)
__f_ = 0;
else
{
__f_ = __as_base(&__buf_);
__f.__f_->__move(__f_);
__f.__f_->destroy();
__f.__f_ = 0;
}
}
template <class _Rp, class... _ArgTypes>
template <class _Fp, class>
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(nullptr)
{
if (__function::__not_null(__f))
{
typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF;
static_assert(
sizeof(_FF) <= sizeof(__buf_),
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
__f_ = ::new (static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
}
}
template <class _Rp, class... _ArgTypes>
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(const function& __f)
{
*this = nullptr;
if (__f.__f_)
{
__f_ = __as_base(&__buf_);
__f.__f_->__clone(__f_);
}
return *this;
}
template <class _Rp, class... _ArgTypes>
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(function&& __f)
{
*this = nullptr;
if (__f.__f_)
{
__f_ = __as_base(&__buf_);
__f.__f_->__move(__f_);
__f.__f_->destroy();
__f.__f_ = 0;
}
return *this;
}
template <class _Rp, class... _ArgTypes>
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT
{
__base* __t = __f_;
__f_ = 0;
if (__t)
__t->destroy();
return *this;
}
template <class _Rp, class... _ArgTypes>
template <class _Fp, class>
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f)
{
*this = nullptr;
if (__function::__not_null(__f))
{
typedef __function::__func<typename decay<_Fp>::type, _Rp(_ArgTypes...)> _FF;
static_assert(
sizeof(_FF) <= sizeof(__buf_),
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
__f_ = ::new (static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
}
return *this;
}
template <class _Rp, class... _ArgTypes>
function<_Rp(_ArgTypes...)>::~function()
{
if (__f_)
__f_->destroy();
}
template <class _Rp, class... _ArgTypes>
void function<_Rp(_ArgTypes...)>::swap(function& __f)
{
if (wistd::addressof(__f) == this)
return;
if (__f_ && __f.__f_)
{
typename aligned_storage<sizeof(__buf_)>::type __tempbuf;
__base* __t = __as_base(&__tempbuf);
__f_->__move(__t);
__f_->destroy();
__f_ = 0;
__f.__f_->__move(__as_base(&__buf_));
__f.__f_->destroy();
__f.__f_ = 0;
__f_ = __as_base(&__buf_);
__t->__move(__as_base(&__f.__buf_));
__t->destroy();
__f.__f_ = __as_base(&__f.__buf_);
}
else if (__f_)
{
__f_->__move(__as_base(&__f.__buf_));
__f_->destroy();
__f_ = 0;
__f.__f_ = __as_base(&__f.__buf_);
}
else if (__f.__f_)
{
__f.__f_->__move(__as_base(&__buf_));
__f.__f_->destroy();
__f.__f_ = 0;
__f_ = __as_base(&__buf_);
}
}
template <class _Rp, class... _ArgTypes>
_Rp function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const
{
if (__f_ == nullptr)
__throw_bad_function_call();
return (*__f_)(wistd::forward<_ArgTypes>(__arg)...);
}
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT
{
return !__f;
}
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT
{
return !__f;
}
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT
{
return (bool)__f;
}
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT
{
return (bool)__f;
}
// Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY void swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y)
{
return __x.swap(__y);
}
template <class _Rp, class... _ArgTypes>
inline __WI_LIBCPP_INLINE_VISIBILITY void swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y)
{
return __x.swap(__y);
}
// std::invoke
template <class _Fn, class... _Args>
typename __invoke_of<_Fn, _Args...>::type invoke(_Fn&& __f, _Args&&... __args)
__WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value))
{
return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...);
}
#else // __WI_LIBCPP_CXX03_LANG
#error wistd::function and wistd::invoke not implemented for pre-C++11
#endif
} // namespace wistd
/// @endcond
#pragma warning(pop)
#endif // _WISTD_FUNCTIONAL_H_

992
d3d11.x/wil/wistd_memory.h Normal file
View File

@@ -0,0 +1,992 @@
// -*- C++ -*-
//===-------------------------- memory ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// STL common functionality
//
// Some aspects of STL are core language concepts that should be used from all C++ code, regardless
// of whether exceptions are enabled in the component. Common library code that expects to be used
// from exception-free components want these concepts, but including STL headers directly introduces
// friction as it requires components not using STL to declare their STL version. Doing so creates
// ambiguity around whether STL use is safe in a particular component and implicitly brings in
// a long list of headers (including <new>) which can create further ambiguity around throwing new
// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has
// the potential to create naming conflicts or other implied dependencies.
//
// To promote the use of these core language concepts outside of STL-based binaries, this file is
// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding
// "std::" namespace STL functions and types should be preferred over these in code that is bound to
// STL. The implementation and naming of all functions are taken directly from STL, instead using
// "wistd" (Windows Implementation std) as the namespace.
//
// Routines in this namespace should always be considered a reflection of the *current* STL implementation
// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here.
//
// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation.
// Only code that is not exception-based and libraries that expect to be utilized across both exception
// and non-exception based code should utilize this functionality.
#ifndef _WISTD_MEMORY_H_
#define _WISTD_MEMORY_H_
// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage
#include "wistd_type_traits.h"
#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
/// @cond
namespace wistd // ("Windows Implementation" std)
{
// allocator_traits
template <class _Tp, class = void>
struct __has_pointer_type : false_type
{
};
template <class _Tp>
struct __has_pointer_type<_Tp, typename __void_t<typename _Tp::pointer>::type> : true_type
{
};
namespace __pointer_type_imp
{
template <class _Tp, class _Dp, bool = __has_pointer_type<_Dp>::value>
struct __pointer_type
{
using type = typename _Dp::pointer;
};
template <class _Tp, class _Dp>
struct __pointer_type<_Tp, _Dp, false>
{
using type = _Tp*;
};
} // namespace __pointer_type_imp
template <class _Tp, class _Dp>
struct __pointer_type
{
using type = typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type;
};
template <class _Tp, int _Idx, bool _CanBeEmptyBase = is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
struct __compressed_pair_elem
{
using _ParamT = _Tp;
using reference = _Tp&;
using const_reference = const _Tp&;
#ifndef __WI_LIBCPP_CXX03_LANG
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_()
{
}
template <class _Up, class = typename enable_if<!is_same<__compressed_pair_elem, typename decay<_Up>::type>::value>::type>
__WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair_elem(_Up&& __u) : __value_(wistd::forward<_Up>(__u))
{
}
// NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed
#else
__WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_()
{
}
__WI_LIBCPP_INLINE_VISIBILITY
__compressed_pair_elem(_ParamT __p) : __value_(wistd::forward<_ParamT>(__p))
{
}
#endif
__WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT
{
return __value_;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY const_reference __get() const WI_NOEXCEPT
{
return __value_;
}
private:
_Tp __value_;
};
template <class _Tp, int _Idx>
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp
{
using _ParamT = _Tp;
using reference = _Tp&;
using const_reference = const _Tp&;
using __value_type = _Tp;
#ifndef __WI_LIBCPP_CXX03_LANG
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() = default;
template <class _Up, class = typename enable_if<!is_same<__compressed_pair_elem, typename decay<_Up>::type>::value>::type>
__WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair_elem(_Up&& __u) : __value_type(wistd::forward<_Up>(__u))
{
}
// NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed
#else
__WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_type()
{
}
__WI_LIBCPP_INLINE_VISIBILITY
__compressed_pair_elem(_ParamT __p) : __value_type(wistd::forward<_ParamT>(__p))
{
}
#endif
__WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT
{
return *this;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY const_reference __get() const WI_NOEXCEPT
{
return *this;
}
};
// Tag used to construct the second element of the compressed pair.
struct __second_tag
{
};
template <class _T1, class _T2>
class __declspec(empty_bases) __compressed_pair : private __compressed_pair_elem<_T1, 0>, private __compressed_pair_elem<_T2, 1>
{
using _Base1 = __compressed_pair_elem<_T1, 0>;
using _Base2 = __compressed_pair_elem<_T2, 1>;
// NOTE: This static assert should never fire because __compressed_pair
// is *almost never* used in a scenario where it's possible for T1 == T2.
// (The exception is wistd::function where it is possible that the function
// object and the allocator have the same type).
static_assert(
(!is_same<_T1, _T2>::value),
"__compressed_pair cannot be instantated when T1 and T2 are the same type; "
"The current implementation is NOT ABI-compatible with the previous "
"implementation for this configuration");
public:
#ifndef __WI_LIBCPP_CXX03_LANG
template <
bool _Dummy = true,
class = typename enable_if<__dependent_type<is_default_constructible<_T1>, _Dummy>::value && __dependent_type<is_default_constructible<_T2>, _Dummy>::value>::type>
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair()
{
}
template <class _Tp, typename enable_if<!is_same<typename decay<_Tp>::type, __compressed_pair>::value, bool>::type = true>
__WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair(_Tp&& __t) : _Base1(wistd::forward<_Tp>(__t)), _Base2()
{
}
template <class _Tp>
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair(__second_tag, _Tp&& __t) :
_Base1(), _Base2(wistd::forward<_Tp>(__t))
{
}
template <class _U1, class _U2>
__WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair(_U1&& __t1, _U2&& __t2) :
_Base1(wistd::forward<_U1>(__t1)), _Base2(wistd::forward<_U2>(__t2))
{
}
// NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed
#else
__WI_LIBCPP_INLINE_VISIBILITY
__compressed_pair()
{
}
__WI_LIBCPP_INLINE_VISIBILITY explicit __compressed_pair(_T1 __t1) : _Base1(wistd::forward<_T1>(__t1))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
__compressed_pair(__second_tag, _T2 __t2) : _Base1(), _Base2(wistd::forward<_T2>(__t2))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
__compressed_pair(_T1 __t1, _T2 __t2) : _Base1(wistd::forward<_T1>(__t1)), _Base2(wistd::forward<_T2>(__t2))
{
}
#endif
__WI_LIBCPP_INLINE_VISIBILITY
typename _Base1::reference first() WI_NOEXCEPT
{
return static_cast<_Base1&>(*this).__get();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY typename _Base1::const_reference first() const WI_NOEXCEPT
{
return static_cast<_Base1 const&>(*this).__get();
}
__WI_LIBCPP_INLINE_VISIBILITY
typename _Base2::reference second() WI_NOEXCEPT
{
return static_cast<_Base2&>(*this).__get();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY typename _Base2::const_reference second() const WI_NOEXCEPT
{
return static_cast<_Base2 const&>(*this).__get();
}
__WI_LIBCPP_INLINE_VISIBILITY
void swap(__compressed_pair& __x) __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value&& __is_nothrow_swappable<_T2>::value)
{
using wistd::swap_wil;
swap_wil(first(), __x.first());
swap_wil(second(), __x.second());
}
};
// Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work
template <class _T1, class _T2>
inline __WI_LIBCPP_INLINE_VISIBILITY void swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y)
__WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value&& __is_nothrow_swappable<_T2>::value)
{
__x.swap(__y);
}
template <class _T1, class _T2>
inline __WI_LIBCPP_INLINE_VISIBILITY void swap_wil(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y)
__WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value&& __is_nothrow_swappable<_T2>::value)
{
__x.swap(__y);
}
// default_delete
template <class _Tp>
struct __WI_LIBCPP_TEMPLATE_VIS default_delete
{
static_assert(!is_function<_Tp>::value, "default_delete cannot be instantiated for function types");
#ifndef __WI_LIBCPP_CXX03_LANG
__WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default;
#else
__WI_LIBCPP_INLINE_VISIBILITY default_delete()
{
}
#endif
template <class _Up>
__WI_LIBCPP_INLINE_VISIBILITY default_delete(
const default_delete<_Up>&, typename enable_if<is_convertible<_Up*, _Tp*>::value>::type* = nullptr) WI_NOEXCEPT
{
}
__WI_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const WI_NOEXCEPT
{
static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
static_assert(!is_void<_Tp>::value, "default_delete can not delete incomplete type");
delete __ptr;
}
};
template <class _Tp>
struct __WI_LIBCPP_TEMPLATE_VIS default_delete<_Tp[]>
{
private:
template <class _Up>
struct _EnableIfConvertible : enable_if<is_convertible<_Up (*)[], _Tp (*)[]>::value>
{
};
public:
#ifndef __WI_LIBCPP_CXX03_LANG
__WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default;
#else
__WI_LIBCPP_INLINE_VISIBILITY default_delete()
{
}
#endif
template <class _Up>
__WI_LIBCPP_INLINE_VISIBILITY default_delete(const default_delete<_Up[]>&, typename _EnableIfConvertible<_Up>::type* = nullptr) WI_NOEXCEPT
{
}
template <class _Up>
__WI_LIBCPP_INLINE_VISIBILITY typename _EnableIfConvertible<_Up>::type operator()(_Up* __ptr) const WI_NOEXCEPT
{
static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
static_assert(!is_void<_Tp>::value, "default_delete can not delete void type");
delete[] __ptr;
}
};
#ifndef __WI_LIBCPP_CXX03_LANG
template <class _Deleter>
struct __unique_ptr_deleter_sfinae
{
static_assert(!is_reference<_Deleter>::value, "incorrect specialization");
using __lval_ref_type = const _Deleter&;
using __good_rval_ref_type = _Deleter&&;
using __enable_rval_overload = true_type;
};
template <class _Deleter>
struct __unique_ptr_deleter_sfinae<_Deleter const&>
{
using __lval_ref_type = const _Deleter&;
using __bad_rval_ref_type = const _Deleter&&;
using __enable_rval_overload = false_type;
};
template <class _Deleter>
struct __unique_ptr_deleter_sfinae<_Deleter&>
{
using __lval_ref_type = _Deleter&;
using __bad_rval_ref_type = _Deleter&&;
using __enable_rval_overload = false_type;
};
#endif // !defined(__WI_LIBCPP_CXX03_LANG)
template <class _Tp, class _Dp = default_delete<_Tp>>
class __WI_LIBCPP_TEMPLATE_VIS unique_ptr
{
public:
using element_type = _Tp;
using deleter_type = _Dp;
using pointer = typename __pointer_type<_Tp, deleter_type>::type;
static_assert(!is_rvalue_reference<deleter_type>::value, "the specified deleter type cannot be an rvalue reference");
private:
__compressed_pair<pointer, deleter_type> __ptr_;
struct __nat
{
int __for_bool_;
};
#ifndef __WI_LIBCPP_CXX03_LANG
using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>;
template <bool _Dummy>
using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type;
template <bool _Dummy>
using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type;
template <bool _Dummy>
using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type;
template <bool _Dummy, class _Deleter = typename __dependent_type<__identity<deleter_type>, _Dummy>::type>
using _EnableIfDeleterDefaultConstructible =
typename enable_if<is_default_constructible<_Deleter>::value && !is_pointer<_Deleter>::value>::type;
template <class _ArgType>
using _EnableIfDeleterConstructible = typename enable_if<is_constructible<deleter_type, _ArgType>::value>::type;
template <class _UPtr, class _Up>
using _EnableIfMoveConvertible =
typename enable_if<is_convertible<typename _UPtr::pointer, pointer>::value && !is_array<_Up>::value>::type;
template <class _UDel>
using _EnableIfDeleterConvertible =
typename enable_if<(is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value)>::type;
template <class _UDel>
using _EnableIfDeleterAssignable = typename enable_if<is_assignable<_Dp&, _UDel&&>::value>::type;
public:
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>>
__WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer())
{
}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>>
__WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer())
{
}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>>
__WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) WI_NOEXCEPT : __ptr_(__p)
{
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d)
{
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, wistd::move(__d))
{
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_BadRValRefType<_Dummy>>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete;
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(unique_ptr&& __u) WI_NOEXCEPT : __ptr_(__u.release(), wistd::forward<deleter_type>(__u.get_deleter()))
{
}
template <class _Up, class _Ep, class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>, class = _EnableIfDeleterConvertible<_Ep>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT
: __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter()))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT
{
reset(__u.release());
__ptr_.second() = wistd::forward<deleter_type>(__u.get_deleter());
return *this;
}
template <class _Up, class _Ep, class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>, class = _EnableIfDeleterAssignable<_Ep>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT
{
reset(__u.release());
__ptr_.second() = wistd::forward<_Ep>(__u.get_deleter());
return *this;
}
#else // __WI_LIBCPP_CXX03_LANG
private:
unique_ptr(unique_ptr&);
template <class _Up, class _Ep>
unique_ptr(unique_ptr<_Up, _Ep>&);
unique_ptr& operator=(unique_ptr&);
template <class _Up, class _Ep>
unique_ptr& operator=(unique_ptr<_Up, _Ep>&);
public:
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr() : __ptr_(pointer())
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
static_assert(is_default_constructible<deleter_type>::value, "unique_ptr::deleter_type is not default constructible");
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(nullptr_t) : __ptr_(pointer())
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
}
__WI_LIBCPP_INLINE_VISIBILITY
explicit unique_ptr(pointer __p) : __ptr_(wistd::move(__p))
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
}
__WI_LIBCPP_INLINE_VISIBILITY
operator __rv<unique_ptr>()
{
return __rv<unique_ptr>(*this);
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(__rv<unique_ptr> __u) : __ptr_(__u->release(), wistd::forward<deleter_type>(__u->get_deleter()))
{
}
template <class _Up, class _Ep>
__WI_LIBCPP_INLINE_VISIBILITY typename enable_if<
!is_array<_Up>::value && is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>::value && is_assignable<deleter_type&, _Ep&>::value,
unique_ptr&>::type
operator=(unique_ptr<_Up, _Ep> __u)
{
reset(__u.release());
__ptr_.second() = wistd::forward<_Ep>(__u.get_deleter());
return *this;
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(pointer __p, deleter_type __d) : __ptr_(wistd::move(__p), wistd::move(__d))
{
}
#endif // __WI_LIBCPP_CXX03_LANG
__WI_LIBCPP_INLINE_VISIBILITY
~unique_ptr()
{
reset();
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr& operator=(nullptr_t) WI_NOEXCEPT
{
reset();
return *this;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator*() const
{
return *__ptr_.first();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY pointer operator->() const WI_NOEXCEPT
{
return __ptr_.first();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY pointer get() const WI_NOEXCEPT
{
return __ptr_.first();
}
__WI_LIBCPP_INLINE_VISIBILITY
deleter_type& get_deleter() WI_NOEXCEPT
{
return __ptr_.second();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY const deleter_type& get_deleter() const WI_NOEXCEPT
{
return __ptr_.second();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT
{
return __ptr_.first() != nullptr;
}
__WI_LIBCPP_INLINE_VISIBILITY
pointer release() WI_NOEXCEPT
{
pointer __t = __ptr_.first();
__ptr_.first() = pointer();
return __t;
}
__WI_LIBCPP_INLINE_VISIBILITY
void reset(pointer __p = pointer()) WI_NOEXCEPT
{
pointer __tmp = __ptr_.first();
__ptr_.first() = __p;
if (__tmp)
__ptr_.second()(__tmp);
}
__WI_LIBCPP_INLINE_VISIBILITY
void swap(unique_ptr& __u) WI_NOEXCEPT
{
__ptr_.swap(__u.__ptr_);
}
};
template <class _Tp, class _Dp>
class __WI_LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
{
public:
using element_type = _Tp;
using deleter_type = _Dp;
using pointer = typename __pointer_type<_Tp, deleter_type>::type;
private:
__compressed_pair<pointer, deleter_type> __ptr_;
template <class _From>
struct _CheckArrayPointerConversion : is_same<_From, pointer>
{
};
template <class _FromElem>
struct _CheckArrayPointerConversion<_FromElem*>
: integral_constant<
bool,
is_same<_FromElem*, pointer>::value ||
(is_same<pointer, element_type*>::value && is_convertible<_FromElem (*)[], element_type (*)[]>::value)>
{
};
#ifndef __WI_LIBCPP_CXX03_LANG
using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>;
template <bool _Dummy>
using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type;
template <bool _Dummy>
using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type;
template <bool _Dummy>
using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type;
template <bool _Dummy, class _Deleter = typename __dependent_type<__identity<deleter_type>, _Dummy>::type>
using _EnableIfDeleterDefaultConstructible =
typename enable_if<is_default_constructible<_Deleter>::value && !is_pointer<_Deleter>::value>::type;
template <class _ArgType>
using _EnableIfDeleterConstructible = typename enable_if<is_constructible<deleter_type, _ArgType>::value>::type;
template <class _Pp>
using _EnableIfPointerConvertible = typename enable_if<_CheckArrayPointerConversion<_Pp>::value>::type;
template <class _UPtr, class _Up, class _ElemT = typename _UPtr::element_type>
using _EnableIfMoveConvertible = typename enable_if<
is_array<_Up>::value && is_same<pointer, element_type*>::value && is_same<typename _UPtr::pointer, _ElemT*>::value &&
is_convertible<_ElemT (*)[], element_type (*)[]>::value>::type;
template <class _UDel>
using _EnableIfDeleterConvertible =
typename enable_if<(is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value)>::type;
template <class _UDel>
using _EnableIfDeleterAssignable = typename enable_if<is_assignable<_Dp&, _UDel&&>::value>::type;
public:
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>>
__WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer())
{
}
template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>>
__WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer())
{
}
template <class _Pp, bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy>, class = _EnableIfPointerConvertible<_Pp>>
__WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(_Pp __p) WI_NOEXCEPT : __ptr_(__p)
{
}
template <class _Pp, bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>, class = _EnableIfPointerConvertible<_Pp>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d)
{
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy>>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(nullptr, __d)
{
}
template <class _Pp, bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>, class = _EnableIfPointerConvertible<_Pp>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, wistd::move(__d))
{
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy>>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(nullptr, wistd::move(__d))
{
static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
}
template <class _Pp, bool _Dummy = true, class = _EnableIfDeleterConstructible<_BadRValRefType<_Dummy>>, class = _EnableIfPointerConvertible<_Pp>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(unique_ptr&& __u) WI_NOEXCEPT : __ptr_(__u.release(), wistd::forward<deleter_type>(__u.get_deleter()))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT
{
reset(__u.release());
__ptr_.second() = wistd::forward<deleter_type>(__u.get_deleter());
return *this;
}
template <class _Up, class _Ep, class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>, class = _EnableIfDeleterConvertible<_Ep>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT
: __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter()))
{
}
template <class _Up, class _Ep, class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>, class = _EnableIfDeleterAssignable<_Ep>>
__WI_LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT
{
reset(__u.release());
__ptr_.second() = wistd::forward<_Ep>(__u.get_deleter());
return *this;
}
#else // __WI_LIBCPP_CXX03_LANG
private:
template <class _Up>
explicit unique_ptr(_Up);
unique_ptr(unique_ptr&);
template <class _Up>
unique_ptr(unique_ptr<_Up>&);
unique_ptr& operator=(unique_ptr&);
template <class _Up>
unique_ptr& operator=(unique_ptr<_Up>&);
template <class _Up>
unique_ptr(
_Up __u,
typename conditional<is_reference<deleter_type>::value, deleter_type, typename add_lvalue_reference<const deleter_type>::type>::type,
typename enable_if<is_convertible<_Up, pointer>::value, __nat>::type = __nat());
public:
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr() : __ptr_(pointer())
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(nullptr_t) : __ptr_(pointer())
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
}
__WI_LIBCPP_INLINE_VISIBILITY
explicit unique_ptr(pointer __p) : __ptr_(__p)
{
static_assert(!is_pointer<deleter_type>::value, "unique_ptr constructed with null function pointer deleter");
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(pointer __p, deleter_type __d) : __ptr_(__p, wistd::forward<deleter_type>(__d))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(nullptr_t, deleter_type __d) : __ptr_(pointer(), wistd::forward<deleter_type>(__d))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
operator __rv<unique_ptr>()
{
return __rv<unique_ptr>(*this);
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr(__rv<unique_ptr> __u) : __ptr_(__u->release(), wistd::forward<deleter_type>(__u->get_deleter()))
{
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr& operator=(__rv<unique_ptr> __u)
{
reset(__u->release());
__ptr_.second() = wistd::forward<deleter_type>(__u->get_deleter());
return *this;
}
#endif // __WI_LIBCPP_CXX03_LANG
public:
__WI_LIBCPP_INLINE_VISIBILITY
~unique_ptr()
{
reset();
}
__WI_LIBCPP_INLINE_VISIBILITY
unique_ptr& operator=(nullptr_t) WI_NOEXCEPT
{
reset();
return *this;
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator[](size_t __i) const
{
return __ptr_.first()[__i];
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY pointer get() const WI_NOEXCEPT
{
return __ptr_.first();
}
__WI_LIBCPP_INLINE_VISIBILITY
deleter_type& get_deleter() WI_NOEXCEPT
{
return __ptr_.second();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY const deleter_type& get_deleter() const WI_NOEXCEPT
{
return __ptr_.second();
}
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT
{
return __ptr_.first() != nullptr;
}
__WI_LIBCPP_INLINE_VISIBILITY
pointer release() WI_NOEXCEPT
{
pointer __t = __ptr_.first();
__ptr_.first() = pointer();
return __t;
}
template <class _Pp>
__WI_LIBCPP_INLINE_VISIBILITY typename enable_if<_CheckArrayPointerConversion<_Pp>::value>::type reset(_Pp __p) WI_NOEXCEPT
{
pointer __tmp = __ptr_.first();
__ptr_.first() = __p;
if (__tmp)
__ptr_.second()(__tmp);
}
__WI_LIBCPP_INLINE_VISIBILITY
void reset(nullptr_t = nullptr) WI_NOEXCEPT
{
pointer __tmp = __ptr_.first();
__ptr_.first() = nullptr;
if (__tmp)
__ptr_.second()(__tmp);
}
__WI_LIBCPP_INLINE_VISIBILITY
void swap(unique_ptr& __u) WI_NOEXCEPT
{
__ptr_.swap(__u.__ptr_);
}
};
// Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work
template <class _Tp, class _Dp>
inline __WI_LIBCPP_INLINE_VISIBILITY typename enable_if<__is_swappable<_Dp>::value, void>::type swap(
unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT
{
__x.swap(__y);
}
template <class _Tp, class _Dp>
inline __WI_LIBCPP_INLINE_VISIBILITY typename enable_if<__is_swappable<_Dp>::value, void>::type swap_wil(
unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT
{
__x.swap(__y);
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
return __x.get() == __y.get();
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
return !(__x == __y);
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
typedef typename unique_ptr<_T1, _D1>::pointer _P1;
typedef typename unique_ptr<_T2, _D2>::pointer _P2;
typedef typename common_type<_P1, _P2>::type _Vp;
return less<_Vp>()(__x.get(), __y.get());
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
return __y < __x;
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
return !(__y < __x);
}
template <class _T1, class _D1, class _T2, class _D2>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y)
{
return !(__x < __y);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT
{
return !__x;
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT
{
return !__x;
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT
{
return static_cast<bool>(__x);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT
{
return static_cast<bool>(__x);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<(const unique_ptr<_T1, _D1>& __x, nullptr_t)
{
typedef typename unique_ptr<_T1, _D1>::pointer _P1;
return less<_P1>()(__x.get(), nullptr);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<(nullptr_t, const unique_ptr<_T1, _D1>& __x)
{
typedef typename unique_ptr<_T1, _D1>::pointer _P1;
return less<_P1>()(nullptr, __x.get());
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1>& __x, nullptr_t)
{
return nullptr < __x;
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(nullptr_t, const unique_ptr<_T1, _D1>& __x)
{
return __x < nullptr;
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1>& __x, nullptr_t)
{
return !(nullptr < __x);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(nullptr_t, const unique_ptr<_T1, _D1>& __x)
{
return !(__x < nullptr);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1>& __x, nullptr_t)
{
return !(__x < nullptr);
}
template <class _T1, class _D1>
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(nullptr_t, const unique_ptr<_T1, _D1>& __x)
{
return !(nullptr < __x);
}
#ifdef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES
template <class _Tp, class _Dp>
inline __WI_LIBCPP_INLINE_VISIBILITY unique_ptr<_Tp, _Dp> move(unique_ptr<_Tp, _Dp>& __t)
{
return unique_ptr<_Tp, _Dp>(__rv<unique_ptr<_Tp, _Dp>>(__t));
}
#endif
} // namespace wistd
/// @endcond
#endif // _WISTD_MEMORY_H_

File diff suppressed because it is too large Load Diff

131
d3d11.x/wil/wrl.h Normal file
View File

@@ -0,0 +1,131 @@
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! Windows Runtime Library Helpers: helpers for constructing RuntimeClass based objects and agile WRL Callback objects
#ifndef __WIL_WRL_INCLUDED
#define __WIL_WRL_INCLUDED
#include <wrl.h>
#include "result.h"
#include "common.h" // wistd type_traits helpers
#include <libloaderapi.h> // GetModuleHandleW
/// @cond
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
/// @endcond
namespace wil
{
#ifdef WIL_ENABLE_EXCEPTIONS
#pragma region Object construction helpers that throw exceptions
/** Used to construct a RuntimeClass based object that uses 2 phase construction.
Construct a RuntimeClass based object that uses 2 phase construction (by implementing
RuntimeClassInitialize() and returning error codes for failures.
@code
// SomeClass uses 2 phase initialization by implementing RuntimeClassInitialize()
auto someClass = MakeAndInitializeOrThrow<SomeClass>(L"input", true);
@endcode
*/
template <typename T, typename... TArgs>
Microsoft::WRL::ComPtr<T> MakeAndInitializeOrThrow(TArgs&&... args)
{
Microsoft::WRL::ComPtr<T> obj;
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<T>(&obj, Microsoft::WRL::Details::Forward<TArgs>(args)...));
return obj;
}
/** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does
not require 2 phase construction).
@code
// SomeClass uses exceptions for error handling in its constructor.
auto someClass = MakeOrThrow<SomeClass>(L"input", true);
@endcode
*/
template <typename T, typename... TArgs>
Microsoft::WRL::ComPtr<T> MakeOrThrow(TArgs&&... args)
{
// This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use.
// Unfortunately this produces false positives as all RuntimeClass derived classes have
// a RuntimeClassInitialize() method from their base class.
// static_assert(!std::is_member_function_pointer<decltype(&T::RuntimeClassInitialize)>::value,
// "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead");
auto obj = Microsoft::WRL::Make<T>(Microsoft::WRL::Details::Forward<TArgs>(args)...);
THROW_IF_NULL_ALLOC(obj.Get());
return obj;
}
#pragma endregion
#endif // WIL_ENABLE_EXCEPTIONS
/** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with
MakeAgileCallback<>. Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() from wil/result.h
to test the result. */
template <typename TDelegateInterface, typename... Args>
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT
{
using namespace Microsoft::WRL;
return Callback<Implements<RuntimeClassFlags<ClassicCom>, TDelegateInterface, FtmBase>>(wistd::forward<Args>(args)...);
}
#ifdef WIL_ENABLE_EXCEPTIONS
template <typename TDelegateInterface, typename... Args>
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallback(Args&&... args)
{
auto result = MakeAgileCallbackNoThrow<TDelegateInterface, Args...>(wistd::forward<Args>(args)...);
THROW_IF_NULL_ALLOC(result);
return result;
}
#endif // WIL_ENABLE_EXCEPTIONS
/** Holds a reference to the host WRL module to prevent it from being unloaded.
Normally, the reference is held implicitly because you are a member function
of a DLL-hosted COM object, or because you retain a strong reference
to some DLL-hosted COM object, but if those do not apply to you, then you
will need to hold a reference explicitly. For examples (and for the C++/WinRT
equivalent), see winrt_module_reference.
*/
struct [[nodiscard]] wrl_module_reference
{
wrl_module_reference()
{
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
{
modulePtr->IncrementObjectCount();
}
else
{
#ifdef GET_MODULE_HANDLE_EX_FLAG_PIN
// If this assertion fails, then you are using wrl_module_reference
// from a DLL that does not host WRL objects, and the module reference
// has no effect.
WI_ASSERT(reinterpret_cast<HMODULE>(&__ImageBase) == GetModuleHandleW(nullptr));
#endif
}
}
wrl_module_reference(wrl_module_reference const&) : wrl_module_reference()
{
}
~wrl_module_reference()
{
if (auto modulePtr = ::Microsoft::WRL::GetModuleBase())
{
modulePtr->DecrementObjectCount();
}
}
};
} // namespace wil
#endif // __WIL_WRL_INCLUDED

122
d3d11.x/xcom/base.h Normal file
View File

@@ -0,0 +1,122 @@
#pragma once
#include <objbase.h>
#include <cstdint>
#include <compare>
#include "wil/result_macros.h"
#ifdef _CPPRTTI
#include <rttidata.h>
#include <typeinfo>
#endif
#ifndef CINTERFACE
struct IUnknownVtbl
{
HRESULT(*QueryInterface)(IUnknown *, REFIID riid, void **ppvObject);
ULONG(*AddRef)(IUnknown *);
ULONG(*Release)(IUnknown *);
};
#endif
struct abi_t
{
uint32_t Major = 0;
uint32_t Minor = 0;
uint32_t Build = 0;
uint32_t Revision = 0;
auto operator<=>(abi_t const &other) const noexcept = default;
bool operator==(abi_t const &other) const noexcept = default;
};
// {7E93844E-159A-4D07-9910-87E9D65ECE00}
static const GUID GUID_UnwrapInterface = { 0x7E93844E, 0x159A, 0x4D07, { 0x99, 0x10, 0x87, 0xE9, 0xD6, 0x5E, 0xCE, 0x00 } };
template<typename T>
using reg_return_t = std::conditional_t<(std::is_class_v<T> || std::is_union_v<T>) && (sizeof(T) <= sizeof(std::uintptr_t)), std::uintptr_t, T>;
template<typename T>
FORCEINLINE reg_return_t<T> to_reg_return(T value)
{
if constexpr (std::is_same_v<T, reg_return_t<T>>)
return value;
reg_return_t<T> reg = {};
memcpy(&reg, &value, sizeof(T));
return reg;
}
namespace xcom
{
namespace impl
{
template<typename T>
inline constexpr GUID guid_v = __uuidof(T);
}
template<typename T>
inline constexpr GUID guid_of() { return impl::guid_v<T>; }
template<template<abi_t> typename T>
inline constexpr GUID guid_of() { return guid_of<T<abi_t{}>>(); }
inline void StubHandler(char const *name, void *object)
{
#ifdef _CPPRTTI
char const *type = object ? ((type_info const *)__RTtypeid(object))->name() : "STUB";
#else
char const *type = "STUB";
#endif
MessageBoxA(nullptr, name, type, MB_ICONERROR);
#ifdef _DEBUG
DebugBreak();
#endif
ExitProcess(0);
}
inline void TodoHandler(char const *name, void *object)
{
#ifdef _CPPRTTI
char const *type = object ? ((type_info const *)__RTtypeid(object))->name() : nullptr;
#else
char const *type = nullptr;
#endif
OutputDebugStringA("TODO: ");
OutputDebugStringA(name);
if (type != nullptr)
{
OutputDebugStringA("(from ");
OutputDebugStringA(type);
OutputDebugStringA(")");
}
OutputDebugStringA("\n");
}
inline HRESULT UnwrapInterface(_In_opt_ IUnknown *pUnknown, _Outptr_ void **ppvObject)
{
HRESULT hr;
if (ppvObject == nullptr)
RETURN_HR(E_POINTER);
if (pUnknown == nullptr)
{
*ppvObject = nullptr;
return S_FALSE;
}
if (SUCCEEDED(hr = pUnknown->QueryInterface(GUID_UnwrapInterface, ppvObject)))
return hr;
*ppvObject = nullptr;
return hr;
}
}
#ifndef DECLARE_UUIDOF_HELPER
#define DECLARE_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) template<> inline constexpr GUID (::xcom::impl::guid_v<type>){a,b,c,{d,e,f,g,h,i,j,k}};
#endif
#define DECLARE_ABI_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) template<> inline constexpr GUID (::xcom::impl::guid_v<type<abi_t{}>>){a,b,c,{d,e,f,g,h,i,j,k}};
#define IMPLEMENT_STUB() ::xcom::StubHandler(__func__, __if_exists(this) { this } __if_not_exists(this) { nullptr })
#define IMPLEMENT_TODO() ::xcom::TodoHandler(__func__, __if_exists(this) { this } __if_not_exists(this) { nullptr })

1
etwplus/CMakeLists.txt Normal file
View File

@@ -0,0 +1 @@
add_library(etwplus SHARED "etwplus.cpp" "etwplus.h")

66
etwplus/etwplus.cpp Normal file
View File

@@ -0,0 +1,66 @@
// etwplus.cpp : Source file for your target.
//
#include "etwplus.h"
EXTERN_C ULONG WINAPI EtxEventWrite(
_In_ PETX_EVENT_DESCRIPTOR EventDescriptor,
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
_In_ REGHANDLE RegHandle,
_In_ ULONG UserDataCount,
_In_opt_ PEVENT_DATA_DESCRIPTOR UserData)
{
UNREFERENCED_PARAMETER(EventDescriptor);
UNREFERENCED_PARAMETER(ProviderDescriptor);
UNREFERENCED_PARAMETER(RegHandle);
UNREFERENCED_PARAMETER(UserDataCount);
UNREFERENCED_PARAMETER(UserData);
return ERROR_SUCCESS;
}
EXTERN_C void WINAPI EtxFillCommonFields_v7(
_Out_ PEVENT_DATA_DESCRIPTOR EventData,
_Out_ PUINT8 Scratch,
_In_ SIZE_T ScratchSize)
{
UNREFERENCED_PARAMETER(EventData);
UNREFERENCED_PARAMETER(Scratch);
UNREFERENCED_PARAMETER(ScratchSize);
ZeroMemory(EventData, sizeof(*EventData));
}
EXTERN_C ULONG WINAPI EtxRegister(
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
_Out_ PREGHANDLE RegHandle)
{
UNREFERENCED_PARAMETER(ProviderDescriptor);
*RegHandle = 0;
return ERROR_SUCCESS;
}
EXTERN_C void WINAPI EtxResumeUploading()
{
}
EXTERN_C void WINAPI EtxSuspendUploading()
{
}
EXTERN_C ULONG WINAPI EtxUnregister(
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
_In_ PREGHANDLE RegHandle)
{
UNREFERENCED_PARAMETER(ProviderDescriptor);
UNREFERENCED_PARAMETER(RegHandle);
return ERROR_SUCCESS;
}
//
// Exports
//
#pragma comment(linker, "/export:EtxEventWrite")
#pragma comment(linker, "/export:EtxFillCommonFields_v7")
#pragma comment(linker, "/export:EtxRegister")
#pragma comment(linker, "/export:EtxResumeUploading")
#pragma comment(linker, "/export:EtxSuspendUploading")
#pragma comment(linker, "/export:EtxUnregister")

46
etwplus/etwplus.h Normal file
View File

@@ -0,0 +1,46 @@
// etwplus.h : Header file for your target.
#pragma once
#include <Windows.h>
#include <evntprov.h>
typedef struct _ETX_FIELD_DESCRIPTOR
{
UINT8 Type : 5;
UINT8 IsLengthField : 1;
} ETX_FIELD_DESCRIPTOR, * PETX_FIELD_DESCRIPTOR, * LPETX_FIELD_DESCRIPTOR;
typedef struct _ETX_EVENT_DESCRIPTOR
{
EVENT_DESCRIPTOR EtwDescriptor;
LPCSTR Name;
LPCSTR SchemaVersion;
ETX_FIELD_DESCRIPTOR const* FieldDescriptors;
UINT8 NumFields;
UINT8 UploadEnabled;
UINT8 CurrentUploadEnabledState;
UINT8 DefaultUploadEnabledState;
INT8 CurrentPopulationSample;
INT8 DefaultPopulationSample;
UINT8 CurrentLatency;
UINT8 DefaultLatency;
UINT8 CurrentPriority;
UINT8 DefaultPriority;
} ETX_EVENT_DESCRIPTOR, * PETX_EVENT_DESCRIPTOR, * LPETX_EVENT_DESCRIPTOR;
typedef struct _ETX_PROVIDER_DESCRIPTOR
{
LPCSTR Name;
GUID Guid;
ULONG NumEvents;
PETX_EVENT_DESCRIPTOR EventDescriptors;
UINT8 UploadEnabled;
UINT8 CurrentUploadEnabledState;
UINT8 DefaultUploadEnabledState;
INT8 CurrentPopulationSample;
INT8 DefaultPopulationSample;
UINT8 CurrentLatency;
UINT8 DefaultLatency;
UINT8 CurrentPriority;
UINT8 DefaultPriority;
} ETX_PROVIDER_DESCRIPTOR, * PETX_PROVIDER_DESCRIPTOR, * LPETX_PROVIDER_DESCRIPTOR;

1
kernelx/CMakeLists.txt Normal file
View File

@@ -0,0 +1 @@
add_library(kernelx SHARED "kernelx.cpp" "kernelx.h" "Logan.h")

470
kernelx/Logan.h Normal file
View File

@@ -0,0 +1,470 @@
#pragma once
#pragma once
#include "kernelx.h"
#include <Windows.h>
#include <thread>
// All of the types were provided by DaZombieKiller, a huge thanks to him!
#include <winioctl.h>
#define FILE_DEVICE_LOGAN 0x00008000
#define LOGAN_DEVICE_PATH "ACPI_HAL#Logan#0#{F764922A-DE30-40A5-A66E-C46CB191A1CD}"
#define LOGAN_DEVICE_WPATH L"ACPI_HAL#Logan#0#{F764922A-DE30-40A5-A66E-C46CB191A1CD}"
// {f764922a-de30-40a5-a66e-c46cb191a1cd}
DEFINE_GUID(GUID_DEVINTERFACE_LOGAN, 0xF764922A, 0xDE30, 0x40A5, 0xA6, 0x6E, 0xC4, 0x6C, 0xB1, 0x91, 0xA1, 0xCD);
//
// IOCTLs
//
#define IOCTL_LOGAN_BASE FILE_DEVICE_LOGAN
#define IOCTL_LOGAN_ALLOC_MAP CTL_CODE(FILE_DEVICE_LOGAN, 0x0801, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_ATTACH_CHANNEL \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0802, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_GET_MEMORY_STATISTICS \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0803, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_GET_NUI_BUFFER_STATE \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0804, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_SET_NUI_MEC_BUFFER_WRITE_OFFSET \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0805, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_LOAD_ACP_FIRMWARE \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0806, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_SET_USB_CAPTURE_STATE \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0807, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_LOGAN_GET_DRIVER_MEMORY \
CTL_CODE(FILE_DEVICE_LOGAN, 0x0808, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
//
// Types
// Genuine names obtained from PDBs
//
// Represents a physical memory address on the APU.
typedef UINT32 APU_ADDRESS;
typedef enum LOGAN_CORE
{
LOGAN_CORE_NONE = 0x00, // (UNCONFIRMED)
LOGAN_CORE_AVP = 0x01, // Audio Vector Processor
LOGAN_CORE_ASP = 0x02, // Audio Scalar Processor
LOGAN_CORE_ACP = 0x03, // Audio Control Processor
LOGAN_CORE_SHAPE = 0xFF, // Scalable Hardware Audio Processing Engine (UNCONFIRMED)
} LOGAN_CORE, *PLOGAN_CORE;
typedef struct LOGAN_COMMAND // HAL representation of a command
{
UINT32 commandType; // Type of the command (LOGAN_COMMAND_TYPE)
APU_ADDRESS apuAddress; // Physical address of the command's data
} LOGAN_COMMAND, *PLOGAN_COMMAND;
typedef struct _LOGAN_COMMAND_INTERNAL // Device representation of a command
{
UINT32 commandType; // Type of the command (LOGAN_COMMAND_TYPE)
APU_ADDRESS apuAddress; // Physical address of the command's data
UINT32 reserved[62];
} LOGAN_COMMAND_INTERNAL, *PLOGAN_COMMAND_INTERNAL;
typedef struct _LOGAN_MESSAGE // HAL representation of a message
{
UINT32 unknown;
UINT32 status;
UINT32 time; // Message creation time
} LOGAN_MESSAGE, *PLOGAN_MESSAGE;
typedef struct _LOGAN_MESSAGE_INTERNAL // Device representation of a message
{
UINT32 unknown0; // If non-zero, causes LoganHAL::RetrieveMessage to return E_FAIL
UINT32 unknown1;
UINT32 status;
UINT32 time; // Message creation time
UINT32 reserved[60];
} LOGAN_MESSAGE_INTERNAL, *PLOGAN_MESSAGE_INTERNAL;
typedef struct LOGAN_RING_BUFFER_DESCRIPTOR
{
UINT32 offsetRead; // Read offset in 256 byte blocks
UINT32 reserved0[63];
UINT32 offsetWrite; // Write offset in 256 byte blocks
APU_ADDRESS apuAddress; // Physical address of ring buffer
UINT32 sizeInBlocks; // Size of buffer in 256 byte blocks
UINT32 reserved1[61];
} LOGAN_RING_BUFFER_DESCRIPTOR, *PLOGAN_RING_BUFFER_DESCRIPTOR;
typedef struct _LOGAN_PHYSICAL_MEMORY
{
LPVOID address; // Virtual address of memory
APU_ADDRESS apuAddress; // Physical address of memory
UINT32 sizeInBytes; // Size of memory in bytes
} LOGAN_PHYSICAL_MEMORY, *PLOGAN_PHYSICAL_MEMORY;
typedef struct _LOGAN_MEMORY_STATS
{
UINT32 unknown[54];
} LOGAN_MEMORY_STATS, *PLOGAN_MEMORY_STATS;
typedef struct _LOGAN_NUI_BUFFER_STATE
{
UINT32 unknown[20];
} LOGAN_NUI_BUFFER_STATE, *PLOGAN_NUI_BUFFER_STATE;
typedef struct LOGAN_CONTEXT_ASP_SILK_ENC_ENCODE
{
UINT32 unknown[6];
} LOGAN_CONTEXT_ASP_SILK_ENC_ENCODE, *PLOGAN_CONTEXT_ASP_SILK_ENC_ENCODE;
typedef struct LOGAN_CONTEXT_ASP_SILK_DEC_DECODE
{
UINT32 unknown[6];
} LOGAN_CONTEXT_ASP_SILK_DEC_DECODE, *PLOGAN_CONTEXT_ASP_SILK_DEC_DECODE;
//
// Types
//
#define LOGAN_COMMAND_OFFSET_ASP 0xA0000000
#define LOGAN_COMMAND_OFFSET_ACP 0xD0000000
typedef enum LOGAN_COMMAND_TYPE
{
// AcpHal
LOGAN_COMMAND_TYPE_ACP_INIT = LOGAN_COMMAND_OFFSET_ACP + 0x0,
// SILKHardwareInterfaceImpl::Initialize
LOGAN_COMMAND_TYPE_ASP_0 = LOGAN_COMMAND_OFFSET_ASP + 0x0,
LOGAN_COMMAND_TYPE_ASP_1 = LOGAN_COMMAND_OFFSET_ASP + 0x1,
LOGAN_COMMAND_TYPE_ASP_5 = LOGAN_COMMAND_OFFSET_ASP + 0x5,
LOGAN_COMMAND_TYPE_ASP_6 = LOGAN_COMMAND_OFFSET_ASP + 0x6,
// SILKHardwareInterfaceImpl::xa_silk_dec_init
LOGAN_COMMAND_TYPE_ASP_2 = LOGAN_COMMAND_OFFSET_ASP + 0x2,
// SILKHardwareInterfaceImpl::xa_silk_dec
LOGAN_COMMAND_TYPE_ASP_4 = LOGAN_COMMAND_OFFSET_ASP + 0x4,
LOGAN_COMMAND_TYPE_ASP_D = LOGAN_COMMAND_OFFSET_ASP + 0xD,
// SILKHardwareInterfaceImpl::xa_silk_enc_init
LOGAN_COMMAND_TYPE_ASP_7 = LOGAN_COMMAND_OFFSET_ASP + 0x7,
// SILKHardwareInterfaceImpl::xa_silk_enc
LOGAN_COMMAND_TYPE_ASP_8 = LOGAN_COMMAND_OFFSET_ASP + 0x8,
} LOGAN_COMMAND_TYPE, *PLOGAN_COMMAND_TYPE;
typedef struct _LOGAN_COMMAND_ACP_INIT
{
UINT32 unknown0; // Always '1'
APU_ADDRESS acpCommandQueue; // Physical address of the ACP internal command queue
APU_ADDRESS unknown1; // 76 bytes of data, zeroed
UINT32 unknown2[2];
} LOGAN_COMMAND_ACP_INIT, *PLOGAN_COMMAND_ACP_INIT;
typedef enum _LOGAN_ALLOC_MAP_FLAGS
{
LOGAN_ALLOC_MAP_FLAG_NONE = 0,
LOGAN_ALLOC_MAP_FLAG_NOCACHE = 1 << 0, // Allocated memory will not be cached
} LOGAN_ALLOC_MAP_FLAGS, *PLOGAN_ALLOC_MAP_FLAGS;
typedef struct _LOGAN_IOCTL_IN_ALLOC_MAP
{
UINT32 sizeInBytes; // Number of bytes to allocate (aligned to 4K)
UINT32 flags; // Bitmask of LOGAN_ALLOC_MAP_FLAGS values
LPVOID address; // Virtual address to map APU memory into
LPVOID reserved[2];
} LOGAN_IOCTL_IN_ALLOC_MAP, *PLOGAN_IOCTL_IN_ALLOC_MAP;
typedef struct _LOGAN_IOCTL_OUT_ALLOC_MAP
{
UINT32 allocated; // Number of bytes that were allocated
UINT32 reserved0;
LPVOID address; // Virtual address that was mapped
APU_ADDRESS apuAddress; // Physical address of the mapped memory
UINT32 reserved1[3];
} LOGAN_IOCTL_OUT_ALLOC_MAP, *PLOGAN_IOCTL_OUT_ALLOC_MAP;
typedef struct _LOGAN_TRACE_MESSAGE
{
UINT32 length;
CHAR buffer[252];
} LOGAN_TRACE_MESSAGE, *PLOGAN_TRACE_MESSAGE;
typedef struct _LOGAN_CHANNEL
{
LOGAN_RING_BUFFER_DESCRIPTOR commands; // Command ring buffer
LOGAN_RING_BUFFER_DESCRIPTOR messages; // Message ring buffer
LOGAN_TRACE_MESSAGE trace; // Trace message buffer (debug)
} LOGAN_CHANNEL, *PLOGAN_CHANNEL;
typedef struct _LOGAN_IOCTL_IN_ATTACH_CHANNEL
{
LOGAN_CORE core;
APU_ADDRESS apuAddress; // Physical address of a LOGAN_CHANNEL structure
} LOGAN_IOCTL_IN_ATTACH_CHANNEL, *PLOGAN_IOCTL_IN_ATTACH_CHANNEL;
typedef struct _LOGAN_IOCTL_IN_LOAD_ACP_FIRMWARE
{
UINT32 reserved[3];
} LOGAN_IOCTL_IN_LOAD_ACP_FIRMWARE, *PLOGAN_IOCTL_IN_LOAD_ACP_FIRMWARE;
typedef struct _LOGAN_IOCTL_IN_GET_DRIVER_MEMORY
{
UINT32 type; // [0,3) (LoganHAL::GetXMA uses '1')
UINT32 reserved0[2];
UINT32 unknown0; // '1' when 'type' is not '2'
UINT32 unknown1; // '1' when 'type' is '2'
LOGAN_CORE core;
UINT32 reserved1;
} LOGAN_IOCTL_IN_GET_DRIVER_MEMORY, *PLOGAN_IOCTL_IN_GET_DRIVER_MEMORY;
typedef struct _LOGAN_IOCTL_OUT_GET_DRIVER_MEMORY
{
LPVOID address; // Virtual address of the memory
UINT32 sizeInBytes; // Size of the memory in bytes
APU_ADDRESS apuAddress; // Physical address of the memory
UINT32 reserved[2];
} LOGAN_IOCTL_OUT_GET_DRIVER_MEMORY, *PLOGAN_IOCTL_OUT_GET_DRIVER_MEMORY;
BOOL(WINAPI *TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) = DeviceIoControl;
HANDLE hLoganMap{};
DWORD m_pBumpAllocStart = 0x10000;
LOGAN_PHYSICAL_MEMORY _driverMemory[3];
class LoganHeap
{
public:
PVOID _declspec(dllexport) GetVirtualAddress(_In_ APU_ADDRESS ApuAddress, _In_ SIZE_T SizeInBytes) const;
template <typename T> T *GetVirtualAddress(_In_ APU_ADDRESS ApuAddress, _In_ SIZE_T Count = 1) const;
HRESULT _declspec(dllexport) GetDriverMemory(UINT32 index, LOGAN_PHYSICAL_MEMORY *memory) const;
PVOID _view;
};
template <typename T> void _declspec(dllexport) DispatchLoganCommand(LOGAN_COMMAND_TYPE cmdType, T cmd);
PVOID LoganHeap::GetVirtualAddress(APU_ADDRESS ApuAddress, SIZE_T SizeInBytes) const
{
if (!ApuAddress)
return nullptr;
return (PVOID)((ULONG_PTR)_view + ApuAddress);
}
HRESULT LoganHeap::GetDriverMemory(UINT32 index, LOGAN_PHYSICAL_MEMORY *memory) const
{
*memory = _driverMemory[index];
return S_OK;
}
template <typename T> T *LoganHeap::GetVirtualAddress(APU_ADDRESS ApuAddress, SIZE_T Count) const
{
return (T *)GetVirtualAddress(ApuAddress, sizeof(T) * Count);
}
template <typename T> inline void DispatchLoganCommand(LOGAN_COMMAND_TYPE cmdType, T cmd)
{
if (cmdType == LOGAN_COMMAND_TYPE_ACP_INIT)
{
LOGAN_COMMAND_ACP_INIT *Command = reinterpret_cast<LOGAN_COMMAND_ACP_INIT *>(cmd);
}
}
LoganHeap g_LoganHeap;
DWORD BumpAlloc(_In_ SIZE_T size)
{
DWORD allocatedBlock = m_pBumpAllocStart;
m_pBumpAllocStart += (size + 0xFFFF) & ~0xFFFF;
return allocatedBlock;
}
LPVOID Map(_In_ UINT NumPages, _In_ LPVOID Address, _In_ DWORD ApuAddress, _In_ UINT PageSize)
{
for (UINT i = 0; i < NumPages; i++)
{
LPVOID pageAddress = (LPVOID)((ULONG_PTR)Address + PageSize * i);
UnmapViewOfFileEx(pageAddress, MEM_PRESERVE_PLACEHOLDER);
void *brain = MapViewOfFile3(hLoganMap, nullptr, pageAddress, ApuAddress + PageSize * i, PageSize,
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
void *fart = VirtualAlloc2(nullptr, pageAddress, PageSize, MEM_COMMIT, PAGE_READWRITE, nullptr, 0);
}
return Address;
}
_Use_decl_annotations_ DWORD DispatchGetDriverMemory(DWORD IoControlCode, PVOID InBuffer, DWORD InBufferSize,
PVOID OutBuffer, DWORD OutBufferSize, PDWORD BytesReturned,
LPOVERLAPPED Overlapped)
{
auto In = reinterpret_cast<LOGAN_IOCTL_IN_GET_DRIVER_MEMORY const *>(InBuffer);
auto Out = reinterpret_cast<LOGAN_IOCTL_OUT_GET_DRIVER_MEMORY *>(OutBuffer);
LOGAN_PHYSICAL_MEMORY memory{};
g_LoganHeap.GetDriverMemory(In->type, &memory);
ZeroMemory(Out, sizeof(LOGAN_IOCTL_OUT_GET_DRIVER_MEMORY));
Out->address = memory.address;
Out->apuAddress = memory.apuAddress;
Out->sizeInBytes = memory.sizeInBytes;
if (BytesReturned)
*BytesReturned = sizeof(LOGAN_IOCTL_OUT_GET_DRIVER_MEMORY);
return ERROR_SUCCESS;
}
template <typename T>
static BOOL ReadFromRingBuffer(T *OutBuffer, T *InBuffer, LOGAN_RING_BUFFER_DESCRIPTOR *InBufferDesc)
{
if (InBufferDesc->offsetRead == InBufferDesc->offsetWrite)
return FALSE;
*OutBuffer = InBuffer[InBufferDesc->offsetRead];
InBufferDesc->offsetRead =
InBufferDesc->offsetRead + 1 < InBufferDesc->sizeInBlocks ? InBufferDesc->offsetRead + 1 : 0;
return TRUE;
}
static DWORD WINAPI LoganChannelProc(LPVOID lpThreadParameter)
{
SetThreadDescription(GetCurrentThread(), L"Logan Thread");
auto channel = (LOGAN_CHANNEL *)lpThreadParameter;
auto commands = g_LoganHeap.GetVirtualAddress<LOGAN_COMMAND_INTERNAL>(channel->commands.apuAddress,
channel->commands.sizeInBlocks);
auto messages = g_LoganHeap.GetVirtualAddress<LOGAN_MESSAGE_INTERNAL>(channel->messages.apuAddress,
channel->messages.sizeInBlocks);
do
{
LOGAN_COMMAND_INTERNAL command;
while (ReadFromRingBuffer(&command, commands, &channel->commands))
DispatchLoganCommand((LOGAN_COMMAND_TYPE)command.commandType,
g_LoganHeap.GetVirtualAddress<LOGAN_COMMAND_ACP_INIT>(command.apuAddress));
Sleep(1);
} while (true);
return 0;
}
static ULONGLONG constexpr c_XMemAttributes = 0xEC81000;
HANDLE LoganHandle = nullptr;
EXTERN_C BOOL __stdcall EraDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
if (hDevice != LoganHandle)
{
return DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
}
else
{
SetLastError(ERROR_SUCCESS);
if (dwIoControlCode == IOCTL_LOGAN_ALLOC_MAP) // 0x800E007
{
LOGAN_IOCTL_IN_ALLOC_MAP *InMap = reinterpret_cast<LOGAN_IOCTL_IN_ALLOC_MAP *>(lpInBuffer);
UINT Size = (InMap->sizeInBytes + (0x10000 - 1)) & ~(0x10000 - 1);
UINT NumPages = Size / 0x10000;
DWORD Allocated = BumpAlloc(Size);
LPVOID Mapped = Map(NumPages, InMap->address, Allocated, 0x10000);
LOGAN_IOCTL_OUT_ALLOC_MAP outMap{};
outMap.allocated = InMap->sizeInBytes;
outMap.address = Mapped;
outMap.apuAddress = Allocated;
outMap.reserved0 = 0;
*reinterpret_cast<LOGAN_IOCTL_OUT_ALLOC_MAP *>(lpOutBuffer) = outMap;
*lpBytesReturned = 32;
}
else if (dwIoControlCode == IOCTL_LOGAN_ATTACH_CHANNEL) // 0x800E00B
{
LOGAN_IOCTL_IN_ATTACH_CHANNEL *In = reinterpret_cast<LOGAN_IOCTL_IN_ATTACH_CHANNEL *>(lpInBuffer);
LOGAN_CHANNEL *Channel = g_LoganHeap.GetVirtualAddress<LOGAN_CHANNEL>(In->apuAddress);
std::thread LoganThread(LoganChannelProc, Channel);
LoganThread.detach();
}
else if (dwIoControlCode == IOCTL_LOGAN_GET_MEMORY_STATISTICS)
{
MessageBoxA(NULL, "IOCTL_LOGAN_GET_MEMORY_STATISTICS", "DeviceIoControl", MB_OK);
}
else if (dwIoControlCode == IOCTL_LOGAN_GET_NUI_BUFFER_STATE)
{
MessageBoxA(NULL, "IOCTL_LOGAN_GET_NUI_BUFFER_STATE", "DeviceIoControl", MB_OK);
}
else if (dwIoControlCode == IOCTL_LOGAN_SET_NUI_MEC_BUFFER_WRITE_OFFSET)
{
MessageBoxA(NULL, "IOCTL_LOGAN_SET_NUI_MEC_BUFFER_WRITE_OFFSET", "DeviceIoControl", MB_OK);
}
else if (dwIoControlCode == IOCTL_LOGAN_LOAD_ACP_FIRMWARE)
{
return TRUE;
}
else if (dwIoControlCode == IOCTL_LOGAN_SET_USB_CAPTURE_STATE)
{
MessageBoxA(NULL, "IOCTL_LOGAN_SET_USB_CAPTURE_STATE", "DeviceIoControl", MB_OK);
}
else if (dwIoControlCode == IOCTL_LOGAN_GET_DRIVER_MEMORY)
{
DispatchGetDriverMemory(dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
}
else
{
MessageBoxA(NULL, "Unknown Logan code!", "DeviceIoControl", MB_OK);
}
return TRUE;
}
}
PVOID MemAlloc(_In_ SIZE_T dwSize, _In_ ULONGLONG dwAttributes)
{
auto attr = XALLOC_ATTRIBUTES{dwAttributes};
if (attr.s.dwMemoryType != XALLOC_MEMTYPE_HEAP)
{
DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
if (attr.s.dwPageSize == XALLOC_PAGESIZE_4MB)
flAllocationType |= MEM_4MB_PAGES;
else
flAllocationType |= MEM_LARGE_PAGES;
return EraVirtualAlloc(nullptr, dwSize, flAllocationType, PAGE_READWRITE);
}
void *ptr = _aligned_malloc(dwSize, 1ULL << max(4, attr.s.dwAlignment));
if (ptr)
memset(ptr, 0, dwSize);
return ptr;
}
void LoganInit()
{
hLoganMap = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE,
SEC_RESERVE, 0x20000000, nullptr, nullptr, 0);
for (SIZE_T i = 0; i < 3; i++)
{
_driverMemory[i].sizeInBytes = 0x100000;
_driverMemory[i].address = MemAlloc(_driverMemory[i].sizeInBytes, c_XMemAttributes);
_driverMemory[i].apuAddress = BumpAlloc(_driverMemory[i].sizeInBytes);
UINT Size = (_driverMemory[i].sizeInBytes + ((1ULL << 16) - 1)) & ~((1ULL << 16) - 1);
UINT NumPages = Size / (1ULL << 16);
_driverMemory[i].address = Map(NumPages, _driverMemory[i].address, _driverMemory[i].apuAddress, Size);
}
g_LoganHeap._view = MapViewOfFile(hLoganMap, FILE_MAP_WRITE, 0, 0, 0);
}

1306
kernelx/kernelx.cpp Normal file

File diff suppressed because it is too large Load Diff

215
kernelx/kernelx.h Normal file
View File

@@ -0,0 +1,215 @@
//
// Created by DexrnZacAttack on 1/23/26 using zPc-i2.
//
#ifndef WINDURANGO_KERNEL_H
#define WINDURANGO_KERNEL_H
#include <Windows.h>
#include <bitset>
#include <map>
// Most of those came from XWine1
//(More specifically, SlimEra).
// For Allocation Purposes
#define MEM_GRAPHICS 0x10000000
#define MEM_TITLE 0x40000000
#define PAGE_SIZE_4KB (1ULL << 12)
#define PAGE_SIZE_64K (1ULL << 16)
#define PAGE_SIZE_2MB (1ULL << 21)
#define PAGE_SIZE_4MB (1ULL << 22)
#define MEM_MASK (MEM_COMMIT | MEM_RESERVE | MEM_RESET | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET_UNDO)
#define PAGE_MASK (PAGE_NOACCESS | PAGE_READONLY | PAGE_READWRITE | PAGE_GUARD)
#define MEM_PHYSICAL_SIZE 0x400000000ULL // 16 GiB
static std::bitset<(MEM_PHYSICAL_SIZE >> 16)> XwpPhysicalPages;
static SRWLOCK XwpPhysicalMemoryLock = SRWLOCK_INIT;
static HANDLE XwpPhysicalMemory = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE, SEC_RESERVE, MEM_PHYSICAL_SIZE, nullptr, nullptr, 0);
// ESRAM stuff
#define MEM_ESRAM_SIZE 0x2000000ULL // 32 MiB
static HANDLE XwpEsramMemory = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE, SEC_RESERVE, MEM_ESRAM_SIZE, nullptr, nullptr, 0);
typedef struct _MAPPABLE_MEM
{
ULONG_PTR RegionSize : 63;
ULONG_PTR Is4MBPages : 1;
} MAPPABLE_MEM, *PMAPPABLE_MEM;
static SRWLOCK XwpMappableLock = SRWLOCK_INIT;
static std::map<ULONG_PTR, MAPPABLE_MEM> XwpMappables;
static LPVOID MappableQuery(_In_opt_ LPCVOID lpAddress, _Out_ PMAPPABLE_MEM pMappable)
{
auto it = XwpMappables.upper_bound((ULONG_PTR)lpAddress);
if (it == XwpMappables.begin())
{
*pMappable = {};
return nullptr;
}
--it;
if (it->first + it->second.RegionSize <= (ULONG_PTR)lpAddress)
{
*pMappable = {};
return nullptr;
}
*pMappable = it->second;
return (LPVOID)it->first;
}
static DWORD WIN32_FROM_HRESULT(_In_ HRESULT hr)
{
if (SUCCEEDED(hr))
return ERROR_SUCCESS;
return HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr;
}
typedef enum _CONSOLE_TYPE
{
CONSOLE_TYPE_UNKNOWN,
CONSOLE_TYPE_XBOX_ONE,
CONSOLE_TYPE_XBOX_ONE_S,
CONSOLE_TYPE_XBOX_ONE_X,
CONSOLE_TYPE_XBOX_ONE_X_DEVKIT,
} CONSOLE_TYPE, *PCONSOLE_TYPE, *LPCONSOLE_TYPE;
EXTERN_C CONSOLE_TYPE WINAPI GetConsoleType();
typedef struct _SYSTEMOSVERSIONINFO
{
BYTE MajorVersion;
BYTE MinorVersion;
WORD BuildNumber;
WORD Revision;
} SYSTEMOSVERSIONINFO, *PSYSTEMOSVERSIONINFO, *LPSYSTEMOSVERSIONINFO;
EXTERN_C VOID WINAPI GetSystemOSVersion(_Out_ LPSYSTEMOSVERSIONINFO lpVersionInformation);
typedef struct _PROCESSOR_SCHEDULING_STATISTICS
{
ULONGLONG RunningTime;
ULONGLONG IdleTime;
ULONGLONG GlobalTime;
} PROCESSOR_SCHEDULING_STATISTICS, *PPROCESSOR_SCHEDULING_STATISTICS, *LPPROCESSOR_SCHEDULING_STATISTICS;
EXTERN_C VOID WINAPI QueryProcessorSchedulingStatistics(_Out_ PPROCESSOR_SCHEDULING_STATISTICS lpStatistics);
EXTERN_C BOOL WINAPI SetThreadpoolAffinityMask(_Inout_ PTP_POOL Pool, _In_ DWORD_PTR dwThreadAffinityMask);
EXTERN_C BOOL WINAPI SetThreadName(_In_ HANDLE hThread, _In_ PCWSTR lpThreadName);
EXTERN_C BOOL WINAPI GetThreadName(_In_ HANDLE hThread, _Out_ PWSTR lpThreadName, _In_ SIZE_T dwBufferLength,
_Out_ PSIZE_T pdwReturnLength);
typedef struct _TITLEMEMORYSTATUS
{
DWORD dwLength;
DWORD dwReserved;
ULONGLONG ullTotalMem;
ULONGLONG ullAvailMem;
ULONGLONG ullLegacyUsed;
ULONGLONG ullLegacyPeak;
ULONGLONG ullLegacyAvail;
ULONGLONG ullTitleUsed;
ULONGLONG ullTitleAvail;
ULONGLONG ullLegacyPageTableUsed;
ULONGLONG ullTitlePageTableUsed;
} TITLEMEMORYSTATUS, *PTITLEMEMORYSTATUS, *LPTITLEMEMORYSTATUS;
EXTERN_C BOOL WINAPI TitleMemoryStatus(_Inout_ LPTITLEMEMORYSTATUS lpBuffer);
EXTERN_C BOOL WINAPI JobTitleMemoryStatus(_Inout_ LPTITLEMEMORYSTATUS lpBuffer);
typedef struct _TOOLINGMEMORYSTATUS
{
DWORD dwLength;
DWORD dwReserved;
ULONGLONG ullTotalMem;
ULONGLONG ullAvailMem;
ULONGLONG ulPeakUsage;
ULONGLONG ullPageTableUsage;
} TOOLINGMEMORYSTATUS, *PTOOLINGMEMORYSTATUS, *LPTOOLINGMEMORYSTATUS;
EXTERN_C BOOL WINAPI ToolingMemoryStatus(_Inout_ LPTOOLINGMEMORYSTATUS lpBuffer);
EXTERN_C BOOL WINAPI AllocateTitlePhysicalPages(_In_ HANDLE hProcess, _In_ DWORD flAllocationType,
_Inout_ PULONG_PTR NumberOfPages, _Out_ PULONG_PTR PageArray);
EXTERN_C BOOL WINAPI FreeTitlePhysicalPages(_In_ HANDLE hProcess, _In_ ULONG_PTR NumberOfPages,
_In_ PULONG_PTR PageArray);
EXTERN_C PVOID WINAPI MapTitlePhysicalPages(_In_opt_ PVOID VirtualAddress, _In_ ULONG_PTR NumberOfPages,
_In_ DWORD flAllocationType, _In_ DWORD flProtect,
_In_ PULONG_PTR PageArray);
// This is not a standard ERA function, it is provided for convenience
// to aid in the implementation of the Direct3D D3DMapEsramMemory API.
EXTERN_C HRESULT WINAPI MapTitleEsramPages(_In_ PVOID VirtualAddress, _In_ UINT NumberOfPages,
_In_ DWORD flAllocationType, _In_opt_ UINT const *PageArray);
typedef union _XALLOC_ATTRIBUTES {
ULONGLONG dwAttributes;
struct
{
ULONGLONG dwObjectType : 14;
ULONGLONG dwPageSize : 2;
ULONGLONG dwAllocatorId : 8;
ULONGLONG dwAlignment : 5;
ULONGLONG dwMemoryType : 4;
ULONGLONG reserved : 31;
} s;
} XALLOC_ATTRIBUTES, *PXALLOC_ATTRIBUTES, *LPXALLOC_ATTRIBUTES;
typedef enum _XALLOC_PAGESIZE
{
XALLOC_PAGESIZE_4KB,
XALLOC_PAGESIZE_64KB,
XALLOC_PAGESIZE_4MB,
} XALLOC_PAGESIZE, *PXALLOC_PAGESIZE;
typedef enum _XALLOC_MEMTYPE
{
XALLOC_MEMTYPE_HEAP,
XALLOC_MEMTYPE_GRAPHICS_1,
XALLOC_MEMTYPE_GRAPHICS_2,
XALLOC_MEMTYPE_GRAPHICS_3,
XALLOC_MEMTYPE_GRAPHICS_4,
XALLOC_MEMTYPE_GRAPHICS_5,
XALLOC_MEMTYPE_GRAPHICS_6,
XALLOC_MEMTYPE_PHYSICAL_1,
XALLOC_MEMTYPE_PHYSICAL_2,
XALLOC_MEMTYPE_PHYSICAL_3,
} XALLOC_MEMTYPE, *PXALLOC_MEMTYPE;
EXTERN_C PVOID WINAPI XMemAllocDefault(_In_ SIZE_T dwSize, _In_ ULONGLONG dwAttributes);
EXTERN_C void WINAPI XMemFreeDefault(_In_ PVOID lpAddress, _In_ ULONGLONG dwAttributes);
EXTERN_C PVOID WINAPI XMemAlloc(_In_ SIZE_T dwSize, _In_ ULONGLONG dwAttributes);
EXTERN_C void WINAPI XMemFree(_In_ PVOID lpAddress, _In_ ULONGLONG dwAttributes);
EXTERN_C LPVOID WINAPI EraVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
typedef PVOID WINAPI XMEMALLOC_ROUTINE(_In_ SIZE_T dwSize, _In_ ULONGLONG dwAttributes);
typedef XMEMALLOC_ROUTINE *PXMEMALLOC_ROUTINE, *LPXMEMALLOC_ROUTINE;
typedef void WINAPI XMEMFREE_ROUTINE(_In_ PVOID lpAddress, _In_ ULONGLONG dwAttributes);
typedef XMEMFREE_ROUTINE *PXMEMFREE_ROUTINE, *LPXMEMFREE_ROUTINE;
EXTERN_C void WINAPI XMemSetAllocationHooks(_In_opt_ PXMEMALLOC_ROUTINE pAllocRoutine,
_In_opt_ PXMEMFREE_ROUTINE pFreeRoutine);
// More XMem stuff
CRITICAL_SECTION XmpAllocationHookLock;
static PXMEMALLOC_ROUTINE XmpAllocRoutine = XMemAllocDefault;
static PXMEMFREE_ROUTINE XmpFreeRoutine = XMemFreeDefault;
#endif // WINDURANGO_KERNEL_H

View File

@@ -0,0 +1 @@
{"requests":[{"kind":"cache","version":2},{"kind":"cmakeFiles","version":1},{"kind":"codemodel","version":2},{"kind":"toolchains","version":1}]}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
{
"inputs" :
[
{
"path" : "CMakeLists.txt"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/4.1.1-msvc1/CMakeSystem.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeSystemSpecificInitialize.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows-Initialize.cmake"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/4.1.1-msvc1/CMakeCCompiler.cmake"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/4.1.1-msvc1/CMakeCXXCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeSystemSpecificInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeGenericSystem.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeInitializeConfigs.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/WindowsPaths.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeCInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeLanguageInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/MSVC-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows-MSVC-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows-MSVC.cmake"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/4.1.1-msvc1/CMakeRCCompiler.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeRCInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeCommonLanguageInclude.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Internal/CMakeCLinkerInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Internal/CMakeCommonLinkerInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Linker/MSVC-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Linker/MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Linker/Windows-MSVC-C.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Linker/Windows-MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeCXXInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeLanguageInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/MSVC-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows-MSVC-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Windows-MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakeCommonLanguageInclude.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Internal/CMakeCXXLinkerInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Internal/CMakeCommonLinkerInformation.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Linker/MSVC-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Linker/MSVC.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Linker/Windows-MSVC-CXX.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/Platform/Linker/Windows-MSVC.cmake"
},
{
"path" : "projects/WinDurango.Common/CMakeLists.txt"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/FetchContent.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/shared_internal_commands.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/download.cmake.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/extractfile.cmake.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/RepositoryInfo.txt.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/stepscript.cmake.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/UpdateInfo.txt.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/stepscript.cmake.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/PatchInfo.txt.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/stepscript.cmake.in"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/_deps/json-src/CMakeLists.txt"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/ExternalProject/shared_internal_commands.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/GNUInstallDirs.cmake"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/_deps/json-src/cmake/pkg-config.pc.in"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/CMakePackageConfigHelpers.cmake"
},
{
"isCMake" : true,
"isExternal" : true,
"path" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1/Modules/WriteBasicConfigVersionFile.cmake"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/_deps/json-src/cmake/nlohmann_jsonConfigVersion.cmake.in"
},
{
"isGenerated" : true,
"path" : "out/build/x64-Debug/_deps/json-src/cmake/config.cmake.in"
},
{
"path" : "projects/WinDurango.Implementation.WinRT/CMakeLists.txt"
},
{
"path" : "projects/WinDurango.WinRT/CMakeLists.txt"
},
{
"path" : "etwplus/CMakeLists.txt"
},
{
"path" : "kernelx/CMakeLists.txt"
},
{
"path" : "d3d11.x/CMakeLists.txt"
}
],
"kind" : "cmakeFiles",
"paths" :
{
"build" : "C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug",
"source" : "C:/Users/umidi/source/repos/WinDurango"
},
"version" :
{
"major" : 1,
"minor" : 1
}
}

View File

@@ -0,0 +1,276 @@
{
"configurations" :
[
{
"directories" :
[
{
"build" : ".",
"childIndexes" :
[
1,
3,
4,
5,
6,
7
],
"jsonFile" : "directory-.-Debug-d0094a50bb2071803777.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"projectIndex" : 0,
"source" : ".",
"targetIndexes" :
[
0
]
},
{
"build" : "projects/WinDurango.Common",
"childIndexes" :
[
2
],
"jsonFile" : "directory-projects.WinDurango.Common-Debug-0f7b722c332ee4a42ba5.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 1,
"source" : "projects/WinDurango.Common",
"targetIndexes" :
[
1
]
},
{
"build" : "_deps/json-build",
"jsonFile" : "directory-_deps.json-build-Debug-22ac37aaee65079284db.json",
"minimumCMakeVersion" :
{
"string" : "3.5"
},
"parentIndex" : 1,
"projectIndex" : 2,
"source" : "out/build/x64-Debug/_deps/json-src"
},
{
"build" : "projects/WinDurango.Implementation.WinRT",
"jsonFile" : "directory-projects.WinDurango.Implementation.WinRT-Debug-ff0c9fe633461f5280fa.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 3,
"source" : "projects/WinDurango.Implementation.WinRT",
"targetIndexes" :
[
2
]
},
{
"build" : "projects/WinDurango.WinRT",
"jsonFile" : "directory-projects.WinDurango.WinRT-Debug-250ac47eae54aea70d39.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 4,
"source" : "projects/WinDurango.WinRT",
"targetIndexes" :
[
3
]
},
{
"build" : "etwplus",
"jsonFile" : "directory-etwplus-Debug-61055710974904d7e893.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 0,
"source" : "etwplus",
"targetIndexes" :
[
5
]
},
{
"build" : "kernelx",
"jsonFile" : "directory-kernelx-Debug-1ab2f9f40f4d1d165202.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 0,
"source" : "kernelx",
"targetIndexes" :
[
6
]
},
{
"build" : "d3d11.x",
"jsonFile" : "directory-d3d11.x-Debug-70d84b0307a7460d26b6.json",
"minimumCMakeVersion" :
{
"string" : "4.0"
},
"parentIndex" : 0,
"projectIndex" : 0,
"source" : "d3d11.x",
"targetIndexes" :
[
4
]
}
],
"name" : "Debug",
"projects" :
[
{
"childIndexes" :
[
1,
3,
4
],
"directoryIndexes" :
[
0,
5,
6,
7
],
"name" : "WinDurango",
"targetIndexes" :
[
0,
4,
5,
6
]
},
{
"childIndexes" :
[
2
],
"directoryIndexes" :
[
1
],
"name" : "WinDurango.Common",
"parentIndex" : 0,
"targetIndexes" :
[
1
]
},
{
"directoryIndexes" :
[
2
],
"name" : "nlohmann_json",
"parentIndex" : 1
},
{
"directoryIndexes" :
[
3
],
"name" : "WinDurango.Implementation.WinRT",
"parentIndex" : 0,
"targetIndexes" :
[
2
]
},
{
"directoryIndexes" :
[
4
],
"name" : "WinDurango.WinRT",
"parentIndex" : 0,
"targetIndexes" :
[
3
]
}
],
"targets" :
[
{
"directoryIndex" : 0,
"id" : "WinDurango::@6890427a1f51a3e7e1df",
"jsonFile" : "target-WinDurango-Debug-ce43248c26becb9c876c.json",
"name" : "WinDurango",
"projectIndex" : 0
},
{
"directoryIndex" : 1,
"id" : "WinDurango.Common::@8b1614c16e9f61155cc5",
"jsonFile" : "target-WinDurango.Common-Debug-1c907b1833451c57a815.json",
"name" : "WinDurango.Common",
"projectIndex" : 1
},
{
"directoryIndex" : 3,
"id" : "WinDurango.Implementation.WinRT::@a709d3acf67cd3a3c422",
"jsonFile" : "target-WinDurango.Implementation.WinRT-Debug-872feefe31e086c152dd.json",
"name" : "WinDurango.Implementation.WinRT",
"projectIndex" : 3
},
{
"directoryIndex" : 4,
"id" : "WinDurango.WinRT::@45c147f30586ea4f43a2",
"jsonFile" : "target-WinDurango.WinRT-Debug-3f3b07318d5995aa3b5c.json",
"name" : "WinDurango.WinRT",
"projectIndex" : 4
},
{
"directoryIndex" : 7,
"id" : "d3d11_x::@4fa90ef760f3cfa7a424",
"jsonFile" : "target-d3d11_x-Debug-dd965d5872c3e8527f56.json",
"name" : "d3d11_x",
"projectIndex" : 0
},
{
"directoryIndex" : 5,
"id" : "etwplus::@2b25748f72f7aaa4dfc9",
"jsonFile" : "target-etwplus-Debug-7b88d190ab878f27fce7.json",
"name" : "etwplus",
"projectIndex" : 0
},
{
"directoryIndex" : 6,
"id" : "kernelx::@47a08a042e3f84c0ca17",
"jsonFile" : "target-kernelx-Debug-155dc72ad4c25d803cf7.json",
"name" : "kernelx",
"projectIndex" : 0
}
]
}
],
"kind" : "codemodel",
"paths" :
{
"build" : "C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug",
"source" : "C:/Users/umidi/source/repos/WinDurango"
},
"version" :
{
"major" : 2,
"minor" : 8
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : ".",
"source" : "."
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "_deps/json-build",
"source" : "out/build/x64-Debug/_deps/json-src"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "d3d11.x",
"source" : "d3d11.x"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "etwplus",
"source" : "etwplus"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "kernelx",
"source" : "kernelx"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "projects/WinDurango.Common",
"source" : "projects/WinDurango.Common"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "projects/WinDurango.Implementation.WinRT",
"source" : "projects/WinDurango.Implementation.WinRT"
}
}

View File

@@ -0,0 +1,14 @@
{
"backtraceGraph" :
{
"commands" : [],
"files" : [],
"nodes" : []
},
"installers" : [],
"paths" :
{
"build" : "projects/WinDurango.WinRT",
"source" : "projects/WinDurango.WinRT"
}
}

View File

@@ -0,0 +1,132 @@
{
"cmake" :
{
"generator" :
{
"multiConfig" : false,
"name" : "Ninja"
},
"paths" :
{
"cmake" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/cmake.exe",
"cpack" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/cpack.exe",
"ctest" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/ctest.exe",
"root" : "F:/VS2026/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-4.1"
},
"version" :
{
"isDirty" : false,
"major" : 4,
"minor" : 1,
"patch" : 1,
"string" : "4.1.1-msvc1",
"suffix" : "msvc1"
}
},
"objects" :
[
{
"jsonFile" : "codemodel-v2-68d3d17cbf415c8f0e80.json",
"kind" : "codemodel",
"version" :
{
"major" : 2,
"minor" : 8
}
},
{
"jsonFile" : "cache-v2-ae492d2f1c7fac179a1c.json",
"kind" : "cache",
"version" :
{
"major" : 2,
"minor" : 0
}
},
{
"jsonFile" : "cmakeFiles-v1-413b36039ef7ab75ddfb.json",
"kind" : "cmakeFiles",
"version" :
{
"major" : 1,
"minor" : 1
}
},
{
"jsonFile" : "toolchains-v1-ac7f6c639a38a82be393.json",
"kind" : "toolchains",
"version" :
{
"major" : 1,
"minor" : 0
}
}
],
"reply" :
{
"client-MicrosoftVS" :
{
"query.json" :
{
"requests" :
[
{
"kind" : "cache",
"version" : 2
},
{
"kind" : "cmakeFiles",
"version" : 1
},
{
"kind" : "codemodel",
"version" : 2
},
{
"kind" : "toolchains",
"version" : 1
}
],
"responses" :
[
{
"jsonFile" : "cache-v2-ae492d2f1c7fac179a1c.json",
"kind" : "cache",
"version" :
{
"major" : 2,
"minor" : 0
}
},
{
"jsonFile" : "cmakeFiles-v1-413b36039ef7ab75ddfb.json",
"kind" : "cmakeFiles",
"version" :
{
"major" : 1,
"minor" : 1
}
},
{
"jsonFile" : "codemodel-v2-68d3d17cbf415c8f0e80.json",
"kind" : "codemodel",
"version" :
{
"major" : 2,
"minor" : 8
}
},
{
"jsonFile" : "toolchains-v1-ac7f6c639a38a82be393.json",
"kind" : "toolchains",
"version" :
{
"major" : 1,
"minor" : 0
}
}
]
}
}
}
}

View File

@@ -0,0 +1,84 @@
{
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_custom_target"
],
"files" :
[
"CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 12,
"parent" : 0
}
]
},
"dependencies" :
[
{
"id" : "WinDurango.Common::@8b1614c16e9f61155cc5"
},
{
"id" : "WinDurango.Implementation.WinRT::@a709d3acf67cd3a3c422"
},
{
"id" : "WinDurango.WinRT::@45c147f30586ea4f43a2"
},
{
"id" : "etwplus::@2b25748f72f7aaa4dfc9"
},
{
"id" : "kernelx::@47a08a042e3f84c0ca17"
}
],
"id" : "WinDurango::@6890427a1f51a3e7e1df",
"name" : "WinDurango",
"paths" :
{
"build" : ".",
"source" : "."
},
"sourceGroups" :
[
{
"name" : "",
"sourceIndexes" :
[
0
]
},
{
"name" : "CMake Rules",
"sourceIndexes" :
[
1
]
}
],
"sources" :
[
{
"backtrace" : 1,
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/WinDurango",
"sourceGroupIndex" : 0
},
{
"backtrace" : 0,
"isGenerated" : true,
"path" : "out/build/x64-Debug/CMakeFiles/WinDurango.rule",
"sourceGroupIndex" : 1
}
],
"type" : "UTILITY"
}

View File

@@ -0,0 +1,222 @@
{
"artifacts" :
[
{
"path" : "projects/WinDurango.Common/WinDurango.Common.dll"
},
{
"path" : "projects/WinDurango.Common/WinDurango.Common.lib"
},
{
"path" : "projects/WinDurango.Common/WinDurango.Common.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library",
"add_compile_definitions",
"target_compile_definitions",
"target_include_directories",
"target_link_libraries"
],
"files" :
[
"projects/WinDurango.Common/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 24,
"parent" : 0
},
{
"command" : 1,
"file" : 0,
"line" : 9,
"parent" : 0
},
{
"command" : 2,
"file" : 0,
"line" : 31,
"parent" : 0
},
{
"command" : 3,
"file" : 0,
"line" : 25,
"parent" : 0
},
{
"command" : 4,
"file" : 0,
"line" : 29,
"parent" : 0
}
]
},
"compileGroups" :
[
{
"compileCommandFragments" :
[
{
"fragment" : "/DWIN32 /D_WINDOWS /EHsc /Ob0 /Od -std:c++20 -MDd -RTC1 -Zi"
}
],
"defines" :
[
{
"backtrace" : 2,
"define" : "WD_API_EXPORTS"
},
{
"backtrace" : 3,
"define" : "WINDURANGO_COMMON_COMPILER_NAME=\"MSVC\""
},
{
"backtrace" : 3,
"define" : "WINDURANGO_COMMON_PLATFORM_ARCH=\"AMD64\""
},
{
"backtrace" : 3,
"define" : "WINDURANGO_COMMON_PLATFORM_NAME=\"Windows\""
},
{
"backtrace" : 3,
"define" : "WINDURANGO_COMMON_RC_VERSION=1,0,0"
},
{
"backtrace" : 3,
"define" : "WINDURANGO_COMMON_VERSION=\"1.0.0-dev.5\""
},
{
"define" : "WinDurango_Common_EXPORTS"
}
],
"includes" :
[
{
"backtrace" : 4,
"path" : "C:/Users/umidi/source/repos/WinDurango/projects/WinDurango.Common/include/WinDurango.Common"
},
{
"backtrace" : 5,
"path" : "C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/_deps/json-src/include"
}
],
"language" : "CXX",
"languageStandard" :
{
"backtraces" :
[
5
],
"standard" : "20"
},
"sourceIndexes" :
[
1
]
}
],
"id" : "WinDurango.Common::@8b1614c16e9f61155cc5",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "WinDurango.Common",
"nameOnDisk" : "WinDurango.Common.dll",
"paths" :
{
"build" : "projects/WinDurango.Common",
"source" : "projects/WinDurango.Common"
},
"sourceGroups" :
[
{
"name" : "Header Files",
"sourceIndexes" :
[
0,
2,
3,
4,
5
]
},
{
"name" : "Source Files",
"sourceIndexes" :
[
1
]
},
{
"name" : "",
"sourceIndexes" :
[
6
]
}
],
"sources" :
[
{
"backtrace" : 1,
"path" : "projects/WinDurango.Common/include/WinDurango.Common/WinDurango.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "projects/WinDurango.Common/src/WinDurango.cpp",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"path" : "projects/WinDurango.Common/include/WinDurango.Common/Config.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "projects/WinDurango.Common/include/WinDurango.Common/Logging.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/Directory.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/File.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 5,
"path" : "out/build/x64-Debug/_deps/json-src/nlohmann_json.natvis",
"sourceGroupIndex" : 2
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,252 @@
{
"artifacts" :
[
{
"path" : "projects/WinDurango.Implementation.WinRT/WinDurango.Implementation.WinRT.dll"
},
{
"path" : "projects/WinDurango.Implementation.WinRT/WinDurango.Implementation.WinRT.lib"
},
{
"path" : "projects/WinDurango.Implementation.WinRT/WinDurango.Implementation.WinRT.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library",
"target_link_libraries",
"add_compile_definitions",
"target_compile_definitions",
"target_include_directories"
],
"files" :
[
"projects/WinDurango.Implementation.WinRT/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 16,
"parent" : 0
},
{
"command" : 1,
"file" : 0,
"line" : 22,
"parent" : 0
},
{
"command" : 2,
"file" : 0,
"line" : 14,
"parent" : 0
},
{
"command" : 3,
"file" : 0,
"line" : 24,
"parent" : 0
},
{
"command" : 4,
"file" : 0,
"line" : 17,
"parent" : 0
}
]
},
"compileGroups" :
[
{
"compileCommandFragments" :
[
{
"fragment" : "/DWIN32 /D_WINDOWS /EHsc /Ob0 /Od -std:c++20 -MDd -RTC1 -Zi"
}
],
"defines" :
[
{
"backtrace" : 3,
"define" : "WDIMPL_API_EXPORTS"
},
{
"backtrace" : 2,
"define" : "WINDURANGO_COMMON_COMPILER_NAME=\"MSVC\""
},
{
"backtrace" : 2,
"define" : "WINDURANGO_COMMON_PLATFORM_ARCH=\"AMD64\""
},
{
"backtrace" : 2,
"define" : "WINDURANGO_COMMON_PLATFORM_NAME=\"Windows\""
},
{
"backtrace" : 2,
"define" : "WINDURANGO_COMMON_RC_VERSION=1,0,0"
},
{
"backtrace" : 2,
"define" : "WINDURANGO_COMMON_VERSION=\"1.0.0-dev.5\""
},
{
"backtrace" : 4,
"define" : "WINDURANGO_IMPLEMENTATION_WINRT_COMPILER_NAME=\"MSVC\""
},
{
"backtrace" : 4,
"define" : "WINDURANGO_IMPLEMENTATION_WINRT_PLATFORM_ARCH=\"AMD64\""
},
{
"backtrace" : 4,
"define" : "WINDURANGO_IMPLEMENTATION_WINRT_PLATFORM_NAME=\"Windows\""
},
{
"backtrace" : 4,
"define" : "WINDURANGO_IMPLEMENTATION_WINRT_RC_VERSION=1,0,0"
},
{
"backtrace" : 4,
"define" : "WINDURANGO_IMPLEMENTATION_WINRT_VERSION=\"1.0.0-dev.1\""
},
{
"define" : "WinDurango_Implementation_WinRT_EXPORTS"
}
],
"includes" :
[
{
"backtrace" : 5,
"path" : "C:/Users/umidi/source/repos/WinDurango/projects/WinDurango.Implementation.WinRT/include/WinDurango.Implementation.WinRT"
},
{
"backtrace" : 5,
"path" : "C:/Users/umidi/source/repos/WinDurango/projects/WinDurango.Implementation.WinRT/../WinDurango.Common/include"
},
{
"backtrace" : 2,
"path" : "C:/Users/umidi/source/repos/WinDurango/projects/WinDurango.Common/include/WinDurango.Common"
},
{
"backtrace" : 2,
"path" : "C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/_deps/json-src/include"
}
],
"language" : "CXX",
"languageStandard" :
{
"backtraces" :
[
2
],
"standard" : "20"
},
"sourceIndexes" :
[
2,
3
]
}
],
"dependencies" :
[
{
"backtrace" : 2,
"id" : "WinDurango.Common::@8b1614c16e9f61155cc5"
}
],
"id" : "WinDurango.Implementation.WinRT::@a709d3acf67cd3a3c422",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"backtrace" : 2,
"fragment" : "projects\\WinDurango.Common\\WinDurango.Common.lib",
"role" : "libraries"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "WinDurango.Implementation.WinRT",
"nameOnDisk" : "WinDurango.Implementation.WinRT.dll",
"paths" :
{
"build" : "projects/WinDurango.Implementation.WinRT",
"source" : "projects/WinDurango.Implementation.WinRT"
},
"sourceGroups" :
[
{
"name" : "Header Files",
"sourceIndexes" :
[
0,
1
]
},
{
"name" : "Source Files",
"sourceIndexes" :
[
2,
3
]
},
{
"name" : "",
"sourceIndexes" :
[
4
]
}
],
"sources" :
[
{
"backtrace" : 1,
"path" : "projects/WinDurango.Implementation.WinRT/include/WinDurango.Implementation.WinRT/Interfaces/Storage/Directory.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "projects/WinDurango.Implementation.WinRT/include/WinDurango.Implementation.WinRT/Interfaces/Storage/File.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "projects/WinDurango.Implementation.WinRT/src/interfaces/Storage/Directory.cpp",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "projects/WinDurango.Implementation.WinRT/src/interfaces/Storage/File.cpp",
"sourceGroupIndex" : 1
},
{
"backtrace" : 2,
"path" : "out/build/x64-Debug/_deps/json-src/nlohmann_json.natvis",
"sourceGroupIndex" : 2
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,111 @@
{
"artifacts" :
[
{
"path" : "projects/WinDurango.WinRT/WinDurango.WinRT.dll"
},
{
"path" : "projects/WinDurango.WinRT/WinDurango.WinRT.lib"
},
{
"path" : "projects/WinDurango.WinRT/WinDurango.WinRT.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library",
"target_link_libraries"
],
"files" :
[
"projects/WinDurango.WinRT/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 14,
"parent" : 0
},
{
"command" : 1,
"file" : 0,
"line" : 20,
"parent" : 0
}
]
},
"dependencies" :
[
{
"backtrace" : 2,
"id" : "WinDurango.Common::@8b1614c16e9f61155cc5"
}
],
"id" : "WinDurango.WinRT::@45c147f30586ea4f43a2",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"backtrace" : 2,
"fragment" : "projects\\WinDurango.Common\\WinDurango.Common.lib",
"role" : "libraries"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "WinDurango.WinRT",
"nameOnDisk" : "WinDurango.WinRT.dll",
"paths" :
{
"build" : "projects/WinDurango.WinRT",
"source" : "projects/WinDurango.WinRT"
},
"sourceGroups" :
[
{
"name" : "Header Files",
"sourceIndexes" :
[
0
]
},
{
"name" : "",
"sourceIndexes" :
[
1
]
}
],
"sources" :
[
{
"backtrace" : 1,
"path" : "projects/WinDurango.WinRT/include/WinDurango.WinRT/stub.h",
"sourceGroupIndex" : 0
},
{
"backtrace" : 2,
"path" : "out/build/x64-Debug/_deps/json-src/nlohmann_json.natvis",
"sourceGroupIndex" : 1
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,179 @@
{
"artifacts" :
[
{
"path" : "d3d11.x/d3d11_x.dll"
},
{
"path" : "d3d11.x/d3d11_x.lib"
},
{
"path" : "d3d11.x/d3d11_x.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library",
"target_link_options"
],
"files" :
[
"d3d11.x/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 1,
"parent" : 0
},
{
"command" : 1,
"file" : 0,
"line" : 3,
"parent" : 0
}
]
},
"compileGroups" :
[
{
"compileCommandFragments" :
[
{
"fragment" : "/DWIN32 /D_WINDOWS /EHsc /Ob0 /Od -std:c++20 -MDd -RTC1 -Zi"
}
],
"defines" :
[
{
"define" : "d3d11_x_EXPORTS"
}
],
"language" : "CXX",
"languageStandard" :
{
"backtraces" :
[
1
],
"standard" : "20"
},
"sourceIndexes" :
[
0,
4,
6
]
}
],
"id" : "d3d11_x::@4fa90ef760f3cfa7a424",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"backtrace" : 2,
"fragment" : "/FORCE:MULTIPLE",
"role" : "flags"
},
{
"fragment" : "/DEF:C:\\Users\\umidi\\source\\repos\\WinDurango\\d3d11.x\\Exports.def",
"role" : "flags"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "d3d11_x",
"nameOnDisk" : "d3d11_x.dll",
"paths" :
{
"build" : "d3d11.x",
"source" : "d3d11.x"
},
"sourceGroups" :
[
{
"name" : "Source Files",
"sourceIndexes" :
[
0,
4,
6,
7
]
},
{
"name" : "Header Files",
"sourceIndexes" :
[
1,
2,
3,
5
]
}
],
"sources" :
[
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "d3d11.x/d3d11.x.cpp",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "d3d11.x/d3d11.x.h",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"path" : "d3d11.x/unknown.g.h",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"path" : "d3d11.x/IGraphicsUnknown.h",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "d3d11.x/IGraphicsUnknown.cpp",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "d3d11.x/IIDExports.h",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "d3d11.x/IIDExports.cpp",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "d3d11.x/Exports.def",
"sourceGroupIndex" : 0
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,123 @@
{
"artifacts" :
[
{
"path" : "etwplus/etwplus.dll"
},
{
"path" : "etwplus/etwplus.lib"
},
{
"path" : "etwplus/etwplus.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library"
],
"files" :
[
"etwplus/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 1,
"parent" : 0
}
]
},
"compileGroups" :
[
{
"compileCommandFragments" :
[
{
"fragment" : "/DWIN32 /D_WINDOWS /EHsc /Ob0 /Od -std:c++20 -MDd -RTC1 -Zi"
}
],
"defines" :
[
{
"define" : "etwplus_EXPORTS"
}
],
"language" : "CXX",
"languageStandard" :
{
"backtraces" :
[
1
],
"standard" : "20"
},
"sourceIndexes" :
[
0
]
}
],
"id" : "etwplus::@2b25748f72f7aaa4dfc9",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "etwplus",
"nameOnDisk" : "etwplus.dll",
"paths" :
{
"build" : "etwplus",
"source" : "etwplus"
},
"sourceGroups" :
[
{
"name" : "Source Files",
"sourceIndexes" :
[
0
]
},
{
"name" : "Header Files",
"sourceIndexes" :
[
1
]
}
],
"sources" :
[
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "etwplus/etwplus.cpp",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "etwplus/etwplus.h",
"sourceGroupIndex" : 1
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,129 @@
{
"artifacts" :
[
{
"path" : "kernelx/kernelx.dll"
},
{
"path" : "kernelx/kernelx.lib"
},
{
"path" : "kernelx/kernelx.pdb"
}
],
"backtrace" : 1,
"backtraceGraph" :
{
"commands" :
[
"add_library"
],
"files" :
[
"kernelx/CMakeLists.txt"
],
"nodes" :
[
{
"file" : 0
},
{
"command" : 0,
"file" : 0,
"line" : 1,
"parent" : 0
}
]
},
"compileGroups" :
[
{
"compileCommandFragments" :
[
{
"fragment" : "/DWIN32 /D_WINDOWS /EHsc /Ob0 /Od -std:c++20 -MDd -RTC1 -Zi"
}
],
"defines" :
[
{
"define" : "kernelx_EXPORTS"
}
],
"language" : "CXX",
"languageStandard" :
{
"backtraces" :
[
1
],
"standard" : "20"
},
"sourceIndexes" :
[
0
]
}
],
"id" : "kernelx::@47a08a042e3f84c0ca17",
"link" :
{
"commandFragments" :
[
{
"fragment" : "/machine:x64 /debug /INCREMENTAL",
"role" : "flags"
},
{
"fragment" : "kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib",
"role" : "libraries"
}
],
"language" : "CXX"
},
"name" : "kernelx",
"nameOnDisk" : "kernelx.dll",
"paths" :
{
"build" : "kernelx",
"source" : "kernelx"
},
"sourceGroups" :
[
{
"name" : "Source Files",
"sourceIndexes" :
[
0
]
},
{
"name" : "Header Files",
"sourceIndexes" :
[
1,
2
]
}
],
"sources" :
[
{
"backtrace" : 1,
"compileGroupIndex" : 0,
"path" : "kernelx/kernelx.cpp",
"sourceGroupIndex" : 0
},
{
"backtrace" : 1,
"path" : "kernelx/kernelx.h",
"sourceGroupIndex" : 1
},
{
"backtrace" : 1,
"path" : "kernelx/Logan.h",
"sourceGroupIndex" : 1
}
],
"type" : "SHARED_LIBRARY"
}

View File

@@ -0,0 +1,78 @@
{
"kind" : "toolchains",
"toolchains" :
[
{
"compiler" :
{
"id" : "MSVC",
"implicit" :
{
"includeDirectories" : [],
"linkDirectories" : [],
"linkFrameworkDirectories" : [],
"linkLibraries" : []
},
"path" : "F:/VS2026/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/cl.exe",
"version" : "19.50.35723.0"
},
"language" : "C",
"sourceFileExtensions" :
[
"c",
"m"
]
},
{
"compiler" :
{
"id" : "MSVC",
"implicit" :
{
"includeDirectories" : [],
"linkDirectories" : [],
"linkFrameworkDirectories" : [],
"linkLibraries" : []
},
"path" : "F:/VS2026/VC/Tools/MSVC/14.50.35717/bin/Hostx64/x64/cl.exe",
"version" : "19.50.35723.0"
},
"language" : "CXX",
"sourceFileExtensions" :
[
"C",
"M",
"c++",
"cc",
"cpp",
"cxx",
"mm",
"mpp",
"CPP",
"ixx",
"cppm",
"ccm",
"cxxm",
"c++m"
]
},
{
"compiler" :
{
"implicit" : {},
"path" : "C:/Program Files (x86)/Windows Kits/10/bin/10.0.26100.0/x64/rc.exe"
},
"language" : "RC",
"sourceFileExtensions" :
[
"rc",
"RC"
]
}
],
"version" :
{
"major" : 1,
"minor" : 0
}
}

Binary file not shown.

View File

@@ -0,0 +1,70 @@
# ninja log v6
29 59 7910590474193355 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/File.cpp.obj.modmap 8fe8ecefebb8b996
7 235 7910615706782040 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/projects/WinDurango.Common/cmake_install.cmake b374a857868906cb
24 66 7910590474143294 projects/WinDurango.Common/CMakeFiles/WinDurango.Common.dir/CXX.dd f47348b31d1b0044
16 192 7910587224117477 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/File.cpp.obj.ddi d4bf425449819f3d
12 197 7910587224082370 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/Directory.cpp.obj.ddi 25e6aa5f1ab409f8
29 59 7910590474193355 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/CXX.dd 8fe8ecefebb8b996
346 1179 7910604202792627 d3d11.x/CMakeFiles/d3d11.x.dir/IGraphicsUnknown.cpp.obj 12de2bfdf025862
32 312 7910605437045593 d3d11.x/CMakeFiles/d3d11.x.dir/d3d11.x.cpp.obj.ddi 61547aeab287d409
42 804 7910587566391325 projects/WinDurango.Common/WinDurango.Common.dll 857c4aa508452a4c
597 2417 7910587229932149 projects/WinDurango.Common/CMakeFiles/WinDurango.Common.dir/src/WinDurango.cpp.obj e0776735bd94cbb3
29 59 7910590474193355 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/CXXModules.json 8fe8ecefebb8b996
291 318 7910588172722043 projects/WinDurango.Kernel/CMakeFiles/WinDurango.Kernel.dir/CXX.dd a1147dd314c1948b
29 59 7910590474193355 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/Directory.cpp.obj.modmap 8fe8ecefebb8b996
216 243 7910615211553338 d3d11.x/CMakeFiles/d3d11.x.dir/CXXModules.json 76f7efc7ff720ae2
32 290 7910588170133398 projects/WinDurango.Kernel/CMakeFiles/WinDurango.Kernel.dir/src/Kernel.cpp.obj.ddi 434de597537151e2
307 621 7910591713021529 etwplus/etwplus.lib 10f5e444d363e898
291 318 7910588172722043 projects/WinDurango.Kernel/CMakeFiles/WinDurango.Kernel.dir/CXXModules.json a1147dd314c1948b
216 243 7910615211553338 d3d11.x/CMakeFiles/d3d11.x.dir/IGraphicsUnknown.cpp.obj.modmap 76f7efc7ff720ae2
291 318 7910588172722043 projects/WinDurango.Kernel/CMakeFiles/WinDurango.Kernel.dir/src/Kernel.cpp.obj.modmap a1147dd314c1948b
8 546 7910587224037260 projects/WinDurango.Common/CMakeFiles/WinDurango.Common.dir/src/WinDurango.cpp.obj.ddi 99dd102cec9fdb3a
24 66 7910590474143294 projects/WinDurango.Common/CMakeFiles/WinDurango.Common.dir/CXXModules.json f47348b31d1b0044
29 298 7910604199624050 d3d11.x/CMakeFiles/d3d11.x.dir/IGraphicsUnknown.cpp.obj.ddi e6496478a53e1a19
24 66 7910590474143294 projects/WinDurango.Common/CMakeFiles/WinDurango.Common.dir/src/WinDurango.cpp.obj.modmap f47348b31d1b0044
583 945 7910596593737934 kernelx/kernelx.lib 5c9ebcb1d7d6748c
262 1913 7910587226585549 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/Directory.cpp.obj 266da5643e14d9c0
265 1921 7910587226615548 projects/WinDurango.Implementation.WinRT/CMakeFiles/WinDurango.Implementation.WinRT.dir/src/interfaces/Storage/File.cpp.obj 30563b7d5342d208
42 804 7910587566391325 projects/WinDurango.Common/WinDurango.Common.lib 857c4aa508452a4c
989 1334 7910590486849664 projects/WinDurango.Kernel/kernelx.dll 7bec9cccde5560f1
804 1248 7910587570674931 projects/WinDurango.Implementation.WinRT/WinDurango.Implementation.WinRT.dll 27f1df9483ab75ac
804 1248 7910587570674931 projects/WinDurango.Implementation.WinRT/WinDurango.Implementation.WinRT.lib 27f1df9483ab75ac
320 1040 7910588173007668 projects/WinDurango.Kernel/CMakeFiles/WinDurango.Kernel.dir/src/Kernel.cpp.obj 138c244326424074
7 235 7910615706906136 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/etwplus/cmake_install.cmake b374a857868906cb
33 264 7910590474233420 projects/WinDurango.Kernel/CMakeFiles/kernelx.dir/src/Kernel.cpp.obj.ddi 6885a779820b7479
264 302 7910590476885521 projects/WinDurango.Kernel/CMakeFiles/kernelx.dir/CXX.dd 25f543df88534b0a
7 235 7910615706852094 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/projects/WinDurango.Implementation.WinRT/cmake_install.cmake b374a857868906cb
264 302 7910590476885521 projects/WinDurango.Kernel/CMakeFiles/kernelx.dir/CXXModules.json 25f543df88534b0a
7 235 7910615706797036 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/_deps/json-build/cmake_install.cmake b374a857868906cb
264 302 7910590476885521 projects/WinDurango.Kernel/CMakeFiles/kernelx.dir/src/Kernel.cpp.obj.modmap 25f543df88534b0a
308 988 7910590476985608 projects/WinDurango.Kernel/CMakeFiles/kernelx.dir/src/Kernel.cpp.obj 3f158bab9875e528
989 1334 7910590486849664 projects/WinDurango.Kernel/kernelx.lib 7bec9cccde5560f1
8 306 7910591707249836 etwplus/CMakeFiles/etwplus.dir/etwplus.cpp.obj a73a5dd7f0519dde
307 621 7910591713021529 etwplus/etwplus.dll 10f5e444d363e898
7 235 7910615707026339 build.ninja b374a857868906cb
7 235 7910615706736923 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/cmake_install.cmake b374a857868906cb
7 235 7910615706867127 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/projects/WinDurango.WinRT/cmake_install.cmake b374a857868906cb
7 235 7910615706936143 C:/Users/umidi/source/repos/WinDurango/out/build/x64-Debug/kernelx/cmake_install.cmake b374a857868906cb
342 1198 7910605440140159 d3d11.x/CMakeFiles/d3d11.x.dir/d3d11.x.cpp.obj ada65fcbfc08a2ce
8 582 7910596584783655 kernelx/CMakeFiles/kernelx.dir/kernelx.cpp.obj aab25d2affd137e0
583 945 7910596593737934 kernelx/kernelx.dll 5c9ebcb1d7d6748c
27 215 7910615209666526 d3d11.x/CMakeFiles/d3d11.x.dir/IIDExports.cpp.obj.ddi d71b308b46f2ef01
216 243 7910615211553338 d3d11.x/CMakeFiles/d3d11.x.dir/CXX.dd 76f7efc7ff720ae2
216 243 7910615211553338 d3d11.x/CMakeFiles/d3d11.x.dir/d3d11.x.cpp.obj.modmap 76f7efc7ff720ae2
216 243 7910615211553338 d3d11.x/CMakeFiles/d3d11.x.dir/IIDExports.cpp.obj.modmap 76f7efc7ff720ae2
244 830 7910615211836738 d3d11.x/CMakeFiles/d3d11.x.dir/IIDExports.cpp.obj b056b68d675b9aa4
831 1154 7910615220729638 d3d11.x/d3d11.x.dll fd9db952b1a57447
831 1154 7910615220729638 d3d11.x/d3d11.x.lib fd9db952b1a57447
38 239 7910615737233753 d3d11.x/CMakeFiles/d3d11_x.dir/IIDExports.cpp.obj.ddi 159dab44cd5a974d
31 317 7910615737158652 d3d11.x/CMakeFiles/d3d11_x.dir/d3d11.x.cpp.obj.ddi a8d76ecc9ab249c0
35 321 7910615737203778 d3d11.x/CMakeFiles/d3d11_x.dir/IGraphicsUnknown.cpp.obj.ddi 29e9575a523ce674
322 373 7910615740545434 d3d11.x/CMakeFiles/d3d11_x.dir/CXX.dd e74a77862ae42c36
322 373 7910615740545434 d3d11.x/CMakeFiles/d3d11_x.dir/CXXModules.json e74a77862ae42c36
322 373 7910615740545434 d3d11.x/CMakeFiles/d3d11_x.dir/d3d11.x.cpp.obj.modmap e74a77862ae42c36
322 373 7910615740545434 d3d11.x/CMakeFiles/d3d11_x.dir/IGraphicsUnknown.cpp.obj.modmap e74a77862ae42c36
322 373 7910615740545434 d3d11.x/CMakeFiles/d3d11_x.dir/IIDExports.cpp.obj.modmap e74a77862ae42c36
387 730 7910615740721981 d3d11.x/CMakeFiles/d3d11_x.dir/IIDExports.cpp.obj 21054c244406a943
384 1266 7910615740686851 d3d11.x/CMakeFiles/d3d11_x.dir/IGraphicsUnknown.cpp.obj 54ce850199357128
380 1270 7910615740656774 d3d11.x/CMakeFiles/d3d11_x.dir/d3d11.x.cpp.obj 8ba0ab17ee537264
1271 1536 7910615752023451 d3d11.x/d3d11_x.dll 96d8b03523087528
1271 1536 7910615752023451 d3d11.x/d3d11_x.lib 96d8b03523087528

View File

@@ -0,0 +1 @@
msvc_x64_x64

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More