From a5c2e29f4ac69eec91bc9bb75b9120e3ba2198d7 Mon Sep 17 00:00:00 2001 From: tylerjaacks Date: Wed, 28 Jan 2026 15:25:57 -0600 Subject: [PATCH] Ran clang-format. --- .../include/WinDurango.Common/Config.h | 37 +- .../Interfaces/Storage/Directory.h | 24 +- .../Interfaces/Storage/File.h | 20 +- .../include/WinDurango.Common/Logging.h | 129 +- .../include/WinDurango.Common/WinDurango.h | 15 +- .../include/WinDurango.Common/exports.h | 4 +- projects/WinDurango.Common/src/Config.cpp | 22 +- projects/WinDurango.Common/src/Logging.cpp | 48 +- projects/WinDurango.Common/src/WinDurango.cpp | 28 +- .../WinDurango.D3D11X/IGraphicsUnknown.h | 7 +- .../include/WinDurango.D3D11X/IIDExports.h | 4 +- .../include/WinDurango.D3D11X/d3d11.x.h | 38 +- .../include/WinDurango.D3D11X/unknown.g.h | 61 +- .../WinDurango.D3D11X/wil/Tracelogging.h | 9746 +++++------- .../include/WinDurango.D3D11X/wil/com.h | 6002 +++---- .../wil/com_apartment_variable.h | 813 +- .../include/WinDurango.D3D11X/wil/common.h | 693 +- .../include/WinDurango.D3D11X/wil/coroutine.h | 1288 +- .../include/WinDurango.D3D11X/wil/cppwinrt.h | 769 +- .../wil/cppwinrt_authoring.h | 500 +- .../WinDurango.D3D11X/wil/cppwinrt_helpers.h | 488 +- .../wil/cppwinrt_notifiable_module_lock.h | 121 +- .../wil/cppwinrt_register_com_server.h | 83 +- .../WinDurango.D3D11X/wil/cppwinrt_wrl.h | 63 +- .../WinDurango.D3D11X/wil/filesystem.h | 2379 +-- .../WinDurango.D3D11X/wil/nt_result_macros.h | 339 +- .../include/WinDurango.D3D11X/wil/registry.h | 6568 ++++---- .../WinDurango.D3D11X/wil/registry_helpers.h | 3258 ++-- .../include/WinDurango.D3D11X/wil/resource.h | 12865 ++++++++-------- .../include/WinDurango.D3D11X/wil/result.h | 2301 +-- .../WinDurango.D3D11X/wil/result_macros.h | 11048 ++++++------- .../WinDurango.D3D11X/wil/result_originate.h | 167 +- .../WinDurango.D3D11X/wil/rpc_helpers.h | 353 +- .../include/WinDurango.D3D11X/wil/safecast.h | 654 +- .../include/WinDurango.D3D11X/wil/stl.h | 344 +- .../WinDurango.D3D11X/wil/token_helpers.h | 1194 +- .../WinDurango.D3D11X/wil/win32_helpers.h | 1833 +-- .../wil/win32_result_macros.h | 269 +- .../include/WinDurango.D3D11X/wil/windowing.h | 228 +- .../include/WinDurango.D3D11X/wil/winrt.h | 3762 ++--- .../WinDurango.D3D11X/wil/wistd_config.h | 187 +- .../WinDurango.D3D11X/wil/wistd_functional.h | 848 +- .../WinDurango.D3D11X/wil/wistd_memory.h | 1642 +- .../WinDurango.D3D11X/wil/wistd_type_traits.h | 6989 ++++----- .../include/WinDurango.D3D11X/wil/wrl.h | 163 +- .../include/WinDurango.D3D11X/xcom/base.h | 66 +- .../src/IGraphicsUnknown.cpp | 9 +- projects/WinDurango.D3D11X/src/IIDExports.cpp | 3 +- projects/WinDurango.D3D11X/src/d3d11.x.cpp | 61 +- .../WinDurangoNative.h | 8 +- .../src/dllmain.cpp | 4 +- .../Interfaces/Storage/Directory.h | 34 +- .../Interfaces/Storage/File.h | 33 +- .../WinDurangoImplWinRT.h | 8 +- .../src/WinRT.cpp | 9 +- .../src/interfaces/Storage/Directory.cpp | 171 +- .../src/interfaces/Storage/File.cpp | 157 +- .../include/WinDurango.KernelX/Hooks.h | 17 +- .../include/WinDurango.KernelX/kernelx.h | 8 +- projects/WinDurango.KernelX/src/Hooks.cpp | 17 +- projects/WinDurango.KernelX/src/dllmain.cpp | 10 +- projects/WinDurango.KernelX/src/kernelx.cpp | 9 +- .../src/WinDurango.MMDevAPI.cpp | 3 +- projects/WinDurango.Testing/App.cpp | 56 +- projects/WinDurango.Testing/pch.h | 6 +- .../WinDurango.WinRT/WinDurangoWinRT.h | 2 +- .../Xbox/Media/GameTransportControls.h | 43 +- ...eTransportControlsButtonPressedEventArgs.h | 11 +- ...ransportControlsPropertyChangedEventArgs.h | 11 +- .../WinDurango.WinRT/src/WinDurangoWinRT.cpp | 56 +- .../Xbox/Media/GameTransportControls.cpp | 126 +- ...ransportControlsButtonPressedEventArgs.cpp | 8 +- ...nsportControlsPropertyChangedEventArgs.cpp | 8 +- .../include/WinDurango.etwplus/etwplus.h | 8 +- projects/WinDurango.etwplus/src/etwplus.cpp | 23 +- 75 files changed, 39131 insertions(+), 40248 deletions(-) diff --git a/projects/WinDurango.Common/include/WinDurango.Common/Config.h b/projects/WinDurango.Common/include/WinDurango.Common/Config.h index f1f6e90..9f35e82 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/Config.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/Config.h @@ -1,36 +1,41 @@ /* * Created by DexrnZacAttack on 1/23/26 using zPc-i2. * WinDurango.Common::Config -*/ + */ #pragma once -#include +#include "Interfaces/Storage/File.h" #include #include -#include "Interfaces/Storage/File.h" +#include /* * TODO: Make it to write back -*/ -namespace wd::common { - class Config { - public: - Config() : pFile(nullptr), RO(false) {} - Config(std::shared_ptr file, bool ReadOnly = false) : pFile(file), RO(ReadOnly) {} + */ +namespace wd::common +{ + class Config + { + public: + Config() : pFile(nullptr), RO(false) + { + } + Config(std::shared_ptr file, bool ReadOnly = false) : pFile(file), RO(ReadOnly) + { + } bool parse(); /* * Operator Overloading * https://en.cppreference.com/w/cpp/language/operators.html - */ - template - T& operator[](std::string node); + */ + template T &operator[](std::string node); - template - bool set(std::string node, T type); - private: + template bool set(std::string node, T type); + + private: std::shared_ptr pFile; bool RO; nlohmann::json data; }; -} +} // namespace wd::common diff --git a/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/Directory.h b/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/Directory.h index 92eae04..67d7994 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/Directory.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/Directory.h @@ -2,32 +2,38 @@ // Created by DexrnZacAttack on 1/23/26 using zPc-i2. // #pragma once +#include "File.h" #include #include -#include "File.h" -namespace wd::common::interfaces::storage { +namespace wd::common::interfaces::storage +{ // TODO should we have separate project for interfaces? /* - * Interface for storage management, to be impl'd for uwp and crossplat + * Interface for storage management, to be impl'd for uwp and crossplat * * We don't need any args for the constructor * nor any vars bc this is an abstraction. */ - class Directory { - public: - Directory() {} + class Directory + { + public: + Directory() + { + } virtual bool open() = 0; - virtual std::shared_ptr CreateFile(std::filesystem::path path) = 0; // todo maybe return stream type, todo can we use this in uwp context??? I forgor + virtual std::shared_ptr CreateFile( + std::filesystem::path + path) = 0; // todo maybe return stream type, todo can we use this in uwp context??? I forgor virtual std::shared_ptr CreateFolder(std::filesystem::path path) = 0; virtual std::filesystem::path dirpath() = 0; - + virtual bool rename(std::string) = 0; virtual bool remove() = 0; virtual bool move(std::filesystem::path path) = 0; virtual bool copy(std::filesystem::path path) = 0; }; -} // wd::common::interfaces::storage \ No newline at end of file +} // namespace wd::common::interfaces::storage \ No newline at end of file diff --git a/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/File.h b/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/File.h index cce49fa..623b392 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/File.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/Interfaces/Storage/File.h @@ -1,17 +1,21 @@ /* * wd::common::interfaces::storage::File -*/ + */ #pragma once -#include #include +#include -namespace wd::common::interfaces::storage { +namespace wd::common::interfaces::storage +{ // TODO should we have separate project for interfaces? /** Interface for storage management, to be impl'd for uwp and crossplat */ - class File { - public: - File() {} + class File + { + public: + File() + { + } virtual bool open() = 0; virtual bool create() = 0; @@ -21,10 +25,10 @@ namespace wd::common::interfaces::storage { virtual std::filesystem::path filepath() = 0; virtual std::filesystem::path fullfilepath() = 0; - + virtual bool rename(std::string) = 0; virtual bool remove() = 0; virtual bool move(std::filesystem::path path) = 0; virtual bool copy(std::filesystem::path path) = 0; }; -} \ No newline at end of file +} // namespace wd::common::interfaces::storage \ No newline at end of file diff --git a/projects/WinDurango.Common/include/WinDurango.Common/Logging.h b/projects/WinDurango.Common/include/WinDurango.Common/Logging.h index 340e82a..93337d3 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/Logging.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/Logging.h @@ -1,99 +1,140 @@ /* * Logging File * WinDurango.Common::Logging -*/ -#include -#include -#include -#include + */ #include "WinDurango.Common/Interfaces/Storage/File.h" #include "WinDurango.Common/exports.h" +#include +#include +#include +#include -namespace wd::common { - class WD_API Logging { - public: - Logging() : pFile(nullptr), isConstructed(false) {} - Logging(std::shared_ptr file) : pFile(file), isConstructed(true) {} +namespace wd::common +{ + class WD_API Logging + { + public: + Logging() : pFile(nullptr), isConstructed(false) + { + } + Logging(std::shared_ptr file) : pFile(file), isConstructed(true) + { + } void Initialize(); void AddLogger(std::string codespace); /* - * Example: - * Log("WinDurango::Common::Storage", "Failed to do smth - Code %s", 5); - * >> [WinDurango::Common::Storage] 11:25AM 26/12/2025 - Failed to do smth - Code 5 - */ - template - void Log(std::string codespace, fmt::format_string fmt, Args&&... args) { - if (!isInitialized) { + * Example: + * Log("WinDurango::Common::Storage", "Failed to do smth - Code %s", 5); + * >> [WinDurango::Common::Storage] 11:25AM 26/12/2025 - Failed to do smth - Code 5 + */ + template void Log(std::string codespace, fmt::format_string fmt, Args &&...args) + { + if (!isInitialized) + { std::cout << "[WinDurango::Common::Logging.Initialize] - Critical: Logging isn't Initiailized\n"; return; } - try { - if (log.find(codespace) != log.end()) { + try + { + if (log.find(codespace) != log.end()) + { log[codespace]->info(fmt, std::forward(args)...); - } else { + } + else + { AddLogger(codespace); log[codespace]->info(fmt, std::forward(args)...); } - } catch (const spdlog::spdlog_ex& e) { + } + catch (const spdlog::spdlog_ex &e) + { std::cout << "[WinDurango::Common::Logging.spdlog] - Critical: " << e.what() << "\n"; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::Logging.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::Logging.(...))] - Critical: Unknown Error\n"; } } - template - void Warn(std::string codespace, fmt::format_string fmt, Args&&... args) { - if (!isInitialized) { + template void Warn(std::string codespace, fmt::format_string fmt, Args &&...args) + { + if (!isInitialized) + { std::cout << "[WinDurango::Common::Logging.Initialize] - Critical: Logging isn't Initiailized\n"; return; } - try { - if (log.find(codespace) != log.end()) { + try + { + if (log.find(codespace) != log.end()) + { log[codespace]->warn(fmt, std::forward(args)...); - } else { + } + else + { AddLogger(codespace); log[codespace]->warn(fmt, std::forward(args)...); } - } catch (const spdlog::spdlog_ex& e) { + } + catch (const spdlog::spdlog_ex &e) + { std::cout << "[WinDurango::Common::Logging.spdlog] - Critical: " << e.what() << "\n"; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::Logging.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::Logging.(...))] - Critical: Unknown Error\n"; } } - template - void Error(std::string codespace, fmt::format_string fmt, Args&&... args) { - if (!isInitialized) { + template void Error(std::string codespace, fmt::format_string fmt, Args &&...args) + { + if (!isInitialized) + { std::cout << "[WinDurango::Common::Logging.Initialize] - Critical: Logging isn't Initiailized\n"; return; } - try { - if (log.find(codespace) != log.end()) { + try + { + if (log.find(codespace) != log.end()) + { log[codespace]->error(fmt, std::forward(args)...); - } else { + } + else + { AddLogger(codespace); log[codespace]->error(fmt, std::forward(args)...); } - } catch (const spdlog::spdlog_ex& e) { + } + catch (const spdlog::spdlog_ex &e) + { std::cout << "[WinDurango::Common::Logging.spdlog] - Critical: " << e.what() << "\n"; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::Logging.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::Logging.(...))] - Critical: Unknown Error\n"; } } - private: + + private: std::unordered_map> log; std::shared_ptr pFile; - public: + + public: bool isConstructed = false; bool isInitialized = false; }; -} \ No newline at end of file +} // namespace wd::common \ No newline at end of file diff --git a/projects/WinDurango.Common/include/WinDurango.Common/WinDurango.h b/projects/WinDurango.Common/include/WinDurango.Common/WinDurango.h index aef797a..a1bce75 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/WinDurango.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/WinDurango.h @@ -2,15 +2,17 @@ // Created by DexrnZacAttack on 1/23/26 using zPc-i2. // #pragma once -#include -#include "Interfaces/Storage/Directory.h" #include "Config.h" +#include "Interfaces/Storage/Directory.h" #include "Logging.h" #include "exports.h" +#include -namespace wd::common { - class WD_API WinDurango { - public: +namespace wd::common +{ + class WD_API WinDurango + { + public: static std::shared_ptr GetInstance(); WinDurango() = default; @@ -21,10 +23,9 @@ namespace wd::common { Config config; Logging log; - private: + private: bool _inited = false; std::shared_ptr rootDir; std::shared_ptr WinDurangoRoot; }; } // namespace wd::common - diff --git a/projects/WinDurango.Common/include/WinDurango.Common/exports.h b/projects/WinDurango.Common/include/WinDurango.Common/exports.h index 688b1f6..8baa736 100644 --- a/projects/WinDurango.Common/include/WinDurango.Common/exports.h +++ b/projects/WinDurango.Common/include/WinDurango.Common/exports.h @@ -1,7 +1,7 @@ #pragma once #ifdef WD_API_EXPORTS - #define WD_API __declspec(dllexport) +#define WD_API __declspec(dllexport) #else - #define WD_API __declspec(dllimport) +#define WD_API __declspec(dllimport) #endif \ No newline at end of file diff --git a/projects/WinDurango.Common/src/Config.cpp b/projects/WinDurango.Common/src/Config.cpp index 8799db5..1c87b6d 100644 --- a/projects/WinDurango.Common/src/Config.cpp +++ b/projects/WinDurango.Common/src/Config.cpp @@ -1,25 +1,31 @@ #include "Config.h" -bool wd::common::Config::parse() { - try { +bool wd::common::Config::parse() +{ + try + { pFile->open(); std::string jsonData = pFile->read(); data = nlohmann::json::parse(jsonData); return true; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { return false; - } catch (...) { + } + catch (...) + { return false; } } -template -T& wd::common::Config::operator[](std::string node) { +template T &wd::common::Config::operator[](std::string node) +{ return data[node]; } -template -bool wd::common::Config::set(std::string node, T type) { +template bool wd::common::Config::set(std::string node, T type) +{ data[node] = type; return true; } \ No newline at end of file diff --git a/projects/WinDurango.Common/src/Logging.cpp b/projects/WinDurango.Common/src/Logging.cpp index 3ed3857..c8bb861 100644 --- a/projects/WinDurango.Common/src/Logging.cpp +++ b/projects/WinDurango.Common/src/Logging.cpp @@ -1,11 +1,14 @@ #include "Logging.h" -void wd::common::Logging::Initialize() { - if (!isConstructed) { +void wd::common::Logging::Initialize() +{ + if (!isConstructed) + { std::cout << "[WinDurango::Common::Logging.Initialize] - Critical: Logging isn't Constructed\n"; return; } - try { + try + { pFile->open(); auto console_sink = std::make_shared(); auto file_sink = std::make_shared(pFile->fullfilepath().string(), true); @@ -13,44 +16,61 @@ void wd::common::Logging::Initialize() { console_sink->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); file_sink->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); - std::shared_ptr logg = std::make_shared("WinDurango", spdlog::sinks_init_list{console_sink, file_sink}); + std::shared_ptr logg = + std::make_shared("WinDurango", spdlog::sinks_init_list{console_sink, file_sink}); log["WinDurango"] = logg; log["WinDurango"]->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); log["WinDurango"]->info("Setting Log File: {}", pFile->fullfilepath().string()); log["WinDurango"]->flush_on(spdlog::level::info); isInitialized = true; - } catch (const spdlog::spdlog_ex& e) { + } + catch (const spdlog::spdlog_ex &e) + { std::cout << "[WinDurango::Common::Logging.spdlog] - Critical: " << e.what() << "\n"; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::Logging.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::Logging.(...))] - Critical: Unknown Error\n"; } } -void wd::common::Logging::AddLogger(std::string codespace) { - if (!isInitialized) { +void wd::common::Logging::AddLogger(std::string codespace) +{ + if (!isInitialized) + { std::cout << "[WinDurango::Common::Logging.Initialize] - Critical: Logging isn't Initiailized\n"; return; } - try { + try + { auto console_sink = std::make_shared(); auto file_sink = std::make_shared(pFile->fullfilepath().string(), true); console_sink->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); file_sink->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); - std::shared_ptr logg = std::make_shared(codespace, spdlog::sinks_init_list{console_sink, file_sink}); + std::shared_ptr logg = + std::make_shared(codespace, spdlog::sinks_init_list{console_sink, file_sink}); log[codespace] = logg; log[codespace]->set_pattern("[%n] [%H:%M:%S] [thread %t] - %^%l%$: %v"); log[codespace]->flush_on(spdlog::level::info); - } catch (const spdlog::spdlog_ex& e) { + } + catch (const spdlog::spdlog_ex &e) + { std::cout << "[WinDurango::Common::Logging.spdlog] - Critical: " << e.what() << "\n"; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::Logging.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::Logging.(...))] - Critical: Unknown Error\n"; } } diff --git a/projects/WinDurango.Common/src/WinDurango.cpp b/projects/WinDurango.Common/src/WinDurango.cpp index fb04c6c..fe406d5 100644 --- a/projects/WinDurango.Common/src/WinDurango.cpp +++ b/projects/WinDurango.Common/src/WinDurango.cpp @@ -7,21 +7,26 @@ namespace wd::common { std::shared_ptr WinDurango::GetInstance() { - static std::shared_ptr Instance = std::make_shared(); // if we don't declare it in src, it will make multiple instances per - // header import in different libs afaik + static std::shared_ptr Instance = + std::make_shared(); // if we don't declare it in src, it will make multiple instances per + // header import in different libs afaik return Instance; } - bool WinDurango::inited() { + bool WinDurango::inited() + { return _inited; } - void WinDurango::Init(std::shared_ptr rootDir) { - if (this->_inited) { + void WinDurango::Init(std::shared_ptr rootDir) + { + if (this->_inited) + { return; } - try { + try + { rootDir->open(); std::time_t timestamp = std::time(nullptr); @@ -34,7 +39,8 @@ namespace wd::common WinDurangoRoot = rootDir->CreateFolder("WinDurango"); WinDurangoRoot->open(); - std::shared_ptr LogFile = WinDurangoRoot->CreateFile("windurango_log_" + date + ".log"); + std::shared_ptr LogFile = + WinDurangoRoot->CreateFile("windurango_log_" + date + ".log"); std::shared_ptr ConfigFile = WinDurangoRoot->CreateFile("windurango.json"); config = Config(ConfigFile); @@ -44,9 +50,13 @@ namespace wd::common log.Initialize(); this->_inited = true; - } catch (const std::exception& e) { + } + catch (const std::exception &e) + { std::cout << "[WinDurango::Common::WinDurango.exception] - Critical: " << e.what() << "\n"; - } catch (...) { + } + catch (...) + { std::cout << "[WinDurango::Common::WinDurango.(...))] - Critical: Unknown Error\n"; } } diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IGraphicsUnknown.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IGraphicsUnknown.h index 3ab2268..fd638bd 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IGraphicsUnknown.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IGraphicsUnknown.h @@ -1,14 +1,13 @@ #pragma once #include "d3d11.x.h" -template -class GraphicsUnknown : public xbox::IGraphicsUnknown +template class GraphicsUnknown : public xbox::IGraphicsUnknown { -public: + public: // // IUnknown // - HRESULT QueryInterface(REFIID riid, void** ppvObject); + HRESULT QueryInterface(REFIID riid, void **ppvObject); ULONG AddRef(); ULONG Release(); }; diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IIDExports.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IIDExports.h index 3c5541b..303c92d 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IIDExports.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/IIDExports.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include extern const IID IID_IPrivateData; extern const IID IID_IGraphicsUnknown; diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/d3d11.x.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/d3d11.x.h index b10783b..840e324 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/d3d11.x.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/d3d11.x.h @@ -1,27 +1,26 @@ #pragma once #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "dxgi.lib") -#pragma comment (lib, "version.lib") -#include -#include +#pragma comment(lib, "version.lib") +#include "unknown.g.h" #include "xcom/base.h" #include #include +#include +#include #include -#include "unknown.g.h" #include -//We use that to know the OS version. +// We use that to know the OS version. abi_t g_ABI{}; -//Immediate Context fence object. +// Immediate Context fence object. BOOL m_Fence = TRUE; -//Multimap for placement update -std::multimap g_ResourceMap; +// Multimap for placement update +std::multimap g_ResourceMap; std::mutex g_ResourceMapMutex; - #pragma comment(lib, "onecore.lib") #pragma comment(lib, "kernel32.lib") @@ -30,24 +29,33 @@ 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); + MessageBoxW(nullptr, + L"Couldn't get the combase version info size! Make sure you have EmbeddedXvd in the game " + L"root/Mount folder.", + L"D3D11.X Error!", MB_OK); } - BYTE* Data = new BYTE[FileVersionSize]; + 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); + 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{}; + VS_FIXEDFILEINFO *pFixedFileInfo{}; UINT Length = 0; - VerQueryValueW(Data, L"\\", (LPVOID*)&pFixedFileInfo, &Length); + 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); + 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; } diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/unknown.g.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/unknown.g.h index 5e66071..6411679 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/unknown.g.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/unknown.g.h @@ -6,28 +6,23 @@ namespace xbox { - template - struct IGraphicsUnknown; + template struct IGraphicsUnknown; - template - struct IGraphicsUnknownVtbl; + template struct IGraphicsUnknownVtbl; - template - struct __declspec(uuid("bcfaae29-e1a2-4b9a-aafc-55b9ff21fa54")) IGraphicsUnwrap; + template struct __declspec(uuid("bcfaae29-e1a2-4b9a-aafc-55b9ff21fa54")) IGraphicsUnwrap; - template - struct IGraphicsUnwrapVtbl; + template struct IGraphicsUnwrapVtbl; namespace details { - template - struct IGraphicsUnknownData + template struct IGraphicsUnknownData { ULONG m_RefCount; }; - template - requires (ABI >= abi_t{ 10,0,14393,2152 } && ABI < abi_t{ 10,0,19041,3453 }) + template + requires(ABI >= abi_t{10, 0, 14393, 2152} && ABI < abi_t{10, 0, 19041, 3453}) struct IGraphicsUnknownData { ULONG m_DeviceIndex : 3; @@ -36,8 +31,8 @@ namespace xbox ULONG m_RefCount; }; - template - requires (ABI >= abi_t{ 10,0,19041,3453 }) + template + requires(ABI >= abi_t{10, 0, 19041, 3453}) struct IGraphicsUnknownData { ULONG m_DeviceIndex : 3; @@ -46,41 +41,39 @@ namespace xbox ULONG m_Reserved : 27; ULONG m_RefCount; }; - } + } // namespace details - template - struct IGraphicsUnknown : details::IGraphicsUnknownData + template struct IGraphicsUnknown : details::IGraphicsUnknownData { - virtual HRESULT QueryInterface(REFIID riid, void** ppvObject) = 0; + virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0; virtual ULONG AddRef() = 0; virtual ULONG Release() = 0; }; - template - struct IGraphicsUnknownVtbl + template struct IGraphicsUnknownVtbl { - HRESULT(*QueryInterface)(void*, REFIID riid, void** ppvObject); - ULONG(*AddRef)(void*); - ULONG(*Release)(void*); + HRESULT (*QueryInterface)(void *, REFIID riid, void **ppvObject); + ULONG (*AddRef)(void *); + ULONG (*Release)(void *); }; - template - struct IGraphicsUnwrap + template struct IGraphicsUnwrap { }; - template - struct IGraphicsUnwrapVtbl + template struct IGraphicsUnwrapVtbl { }; -} +} // namespace xbox -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) +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})) +#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__ diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/Tracelogging.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/Tracelogging.h index ac14e8c..92b9fbe 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/Tracelogging.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/Tracelogging.h @@ -10,7 +10,8 @@ // //********************************************************* //! @file -//! Defines a series of macros and types that simplify authoring and consumption of tracelogging, telemetry, and activities. +//! Defines a series of macros and types that simplify authoring and consumption of tracelogging, telemetry, and +//! activities. #ifndef __WIL_TRACELOGGING_H_INCLUDED /// @cond @@ -30,9 +31,9 @@ #include #endif #undef RESOURCE_SUPPRESS_STL -#include -#include #include +#include +#include #ifndef __WIL_TRACELOGGING_CONFIG_H #include #endif @@ -72,3169 +73,2889 @@ Macro __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(name1, name2): This macro defines a storage link association between two names for use by the TlgReflector static analysis tool. */ -#define __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(name1, name2) \ - __annotation(L"_TlgProviderLink:|" _wiltlg_LSTRINGIZE(__LINE__) L"|Key|" _wiltlg_LSTRINGIZE(name1) L"=" _wiltlg_LSTRINGIZE(name2)) +#define __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(name1, name2) \ + __annotation(L"_TlgProviderLink:|" _wiltlg_LSTRINGIZE(__LINE__) L"|Key|" _wiltlg_LSTRINGIZE( \ + name1) L"=" _wiltlg_LSTRINGIZE(name2)) // Utility macro for writing relevant fields from a wil::FailureInfo structure into a TraceLoggingWrite // statement. Most fields are relevant for telemetry or for simple ETW, but there are a few additional // fields reported via ETW. -#define __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) \ - TraceLoggingUInt32((failure).hr, "hresult", "Failure error code"), \ - TraceLoggingString((failure).pszFile, "fileName", "Source code file name where the error occurred"), \ - TraceLoggingUInt32((failure).uLineNumber, "lineNumber", "Line number within the source code file where the error occurred"), \ - TraceLoggingString((failure).pszModule, "module", "Name of the binary where the error occurred"), \ - TraceLoggingUInt32( \ - static_cast((failure).type), \ - "failureType", \ - "Indicates what type of failure was observed (exception, returned error, logged error or fail fast"), \ - TraceLoggingWideString((failure).pszMessage, "message", "Custom message associated with the failure (if any)"), \ - TraceLoggingUInt32((failure).threadId, "threadId", "Identifier of the thread the error occurred on"), \ - TraceLoggingString((failure).pszCallContext, "callContext", "List of telemetry activities containing this error"), \ - TraceLoggingUInt32( \ - (failure).callContextOriginating.contextId, \ - "originatingContextId", \ - "Identifier for the oldest telemetry activity containing this error"), \ - TraceLoggingString( \ - (failure).callContextOriginating.contextName, \ - "originatingContextName", \ - "Name of the oldest telemetry activity containing this error"), \ - TraceLoggingWideString( \ - (failure).callContextOriginating.contextMessage, \ - "originatingContextMessage", \ - "Custom message associated with the oldest telemetry activity containing this error (if any)"), \ - TraceLoggingUInt32( \ - (failure).callContextCurrent.contextId, "currentContextId", "Identifier for the newest telemetry activity containing this error"), \ - TraceLoggingString( \ - (failure).callContextCurrent.contextName, "currentContextName", "Name of the newest telemetry activity containing this error"), \ - TraceLoggingWideString( \ - (failure).callContextCurrent.contextMessage, \ - "currentContextMessage", \ +#define __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) \ + TraceLoggingUInt32((failure).hr, "hresult", "Failure error code"), \ + TraceLoggingString((failure).pszFile, "fileName", "Source code file name where the error occurred"), \ + TraceLoggingUInt32((failure).uLineNumber, "lineNumber", \ + "Line number within the source code file where the error occurred"), \ + TraceLoggingString((failure).pszModule, "module", "Name of the binary where the error occurred"), \ + TraceLoggingUInt32( \ + static_cast((failure).type), "failureType", \ + "Indicates what type of failure was observed (exception, returned error, logged error or fail fast"), \ + TraceLoggingWideString((failure).pszMessage, "message", \ + "Custom message associated with the failure (if any)"), \ + TraceLoggingUInt32((failure).threadId, "threadId", "Identifier of the thread the error occurred on"), \ + TraceLoggingString((failure).pszCallContext, "callContext", \ + "List of telemetry activities containing this error"), \ + TraceLoggingUInt32((failure).callContextOriginating.contextId, "originatingContextId", \ + "Identifier for the oldest telemetry activity containing this error"), \ + TraceLoggingString((failure).callContextOriginating.contextName, "originatingContextName", \ + "Name of the oldest telemetry activity containing this error"), \ + TraceLoggingWideString( \ + (failure).callContextOriginating.contextMessage, "originatingContextMessage", \ + "Custom message associated with the oldest telemetry activity containing this error (if any)"), \ + TraceLoggingUInt32((failure).callContextCurrent.contextId, "currentContextId", \ + "Identifier for the newest telemetry activity containing this error"), \ + TraceLoggingString((failure).callContextCurrent.contextName, "currentContextName", \ + "Name of the newest telemetry activity containing this error"), \ + TraceLoggingWideString( \ + (failure).callContextCurrent.contextMessage, "currentContextMessage", \ "Custom message associated with the newest telemetry activity containing this error (if any)") -#define __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure), \ - TraceLoggingUInt32(static_cast((failure).failureId), "failureId", "Identifier assigned to this failure"), \ - TraceLoggingUInt32( \ - static_cast((failure).cFailureCount), "failureCount", "Number of failures seen within the binary where the error occurred"), \ +#define __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) \ + __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure), \ + TraceLoggingUInt32(static_cast((failure).failureId), "failureId", \ + "Identifier assigned to this failure"), \ + TraceLoggingUInt32(static_cast((failure).cFailureCount), "failureCount", \ + "Number of failures seen within the binary where the error occurred"), \ TraceLoggingString((failure).pszFunction, "function", "Name of the function where the error occurred") // Activity Start Event (ALL) -#define __ACTIVITY_START_PARAMS() \ - TraceLoggingStruct(1, "wilActivity"), \ +#define __ACTIVITY_START_PARAMS() \ + TraceLoggingStruct(1, "wilActivity"), \ TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on") // Activity Stop Event (SUCCESSFUL or those WITHOUT full failure info -- just hr) // Also utilized for intermediate stop events (a successful call to 'Stop()' from a Split activity -#define __ACTIVITY_STOP_PARAMS(hr) \ - TraceLoggingStruct(2, "wilActivity"), TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ +#define __ACTIVITY_STOP_PARAMS(hr) \ + TraceLoggingStruct(2, "wilActivity"), TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on") // Activity Stop Event (FAILED with full failure info) -#define __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ +#define __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilActivity"), \ +#define __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilActivity"), \ __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) // "ActivityError" tagged event (all distinct FAILURES occurring within the outer activity scope) -#define __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ +#define __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilActivity"), \ +#define __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilActivity"), \ __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) // "ActivityFailure" tagged event (only comes through on TELEMETRY for CallContext activities that have FAILED) -#define __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ +#define __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilActivity"), \ __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_FAILURE_TELEMETRY_PARAMS(hr, contextName, contextMessage) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(4, "wilActivity"), \ - TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ - TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on"), \ - TraceLoggingString(contextName, "currentContextName", "Name of the activity containing this error"), \ - TraceLoggingWideString(contextMessage, "currentContextMessage", "Custom message for the activity containing this error (if any)") +#define __ACTIVITY_FAILURE_TELEMETRY_PARAMS(hr, contextName, contextMessage) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(4, "wilActivity"), \ + TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ + TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on"), \ + TraceLoggingString(contextName, "currentContextName", "Name of the activity containing this error"), \ + TraceLoggingWideString(contextMessage, "currentContextMessage", \ + "Custom message for the activity containing this error (if any)") // "FallbackError" events (all FAILURE events happening outside of ANY activity context) -#define __RESULT_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilResult"), \ +#define __RESULT_TELEMETRY_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(14, "wilResult"), \ __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __RESULT_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilResult"), \ +#define __RESULT_TRACELOGGING_FAILURE_PARAMS(failure) \ + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingStruct(17, "wilResult"), \ __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) /// @endcond namespace wil { -enum class ActivityOptions -{ - None = 0, - TelemetryOnFailure = 0x1, - TraceLoggingOnFailure = 0x2 -}; -DEFINE_ENUM_FLAG_OPERATORS(ActivityOptions) - -template -class ActivityBase; - -/// @cond -namespace details -{ - // Lazy static initialization helper for holding a singleton telemetry class to maintain - // the provider handle. - - template - class static_lazy + enum class ActivityOptions { - public: - void __cdecl cleanup() WI_NOEXCEPT - { - void* pVoid; - BOOL pending; + None = 0, + TelemetryOnFailure = 0x1, + TraceLoggingOnFailure = 0x2 + }; + DEFINE_ENUM_FLAG_OPERATORS(ActivityOptions) - // If object is being constructed on another thread, wait until construction completes. - // Need a memory barrier here (see get() and ~Completer below) so use the result that we - // get from InitOnceBeginInitialize(..., &pVoid, ...) - if (::InitOnceBeginInitialize(&m_initOnce, INIT_ONCE_CHECK_ONLY, &pending, &pVoid) && !pending) + template + class ActivityBase; + + /// @cond + namespace details + { + // Lazy static initialization helper for holding a singleton telemetry class to maintain + // the provider handle. + + template class static_lazy + { + public: + void __cdecl cleanup() WI_NOEXCEPT { - static_cast(pVoid)->~T(); + void *pVoid; + BOOL pending; + + // If object is being constructed on another thread, wait until construction completes. + // Need a memory barrier here (see get() and ~Completer below) so use the result that we + // get from InitOnceBeginInitialize(..., &pVoid, ...) + if (::InitOnceBeginInitialize(&m_initOnce, INIT_ONCE_CHECK_ONLY, &pending, &pVoid) && !pending) + { + static_cast(pVoid)->~T(); + } } - } - T* get(void(__cdecl* cleanupFunc)(void)) WI_NOEXCEPT - { - void* pVoid{}; - BOOL pending; - if (::InitOnceBeginInitialize(&m_initOnce, 0, &pending, &pVoid) && pending) + T *get(void(__cdecl *cleanupFunc)(void)) WI_NOEXCEPT { - // Don't do anything non-trivial from DllMain, fail fast. - // Some 3rd party code in IE calls shell functions this way, so we can only enforce - // this in DEBUG. + void *pVoid{}; + BOOL pending; + if (::InitOnceBeginInitialize(&m_initOnce, 0, &pending, &pVoid) && pending) + { + // Don't do anything non-trivial from DllMain, fail fast. + // Some 3rd party code in IE calls shell functions this way, so we can only enforce + // this in DEBUG. #ifdef DEBUG - FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT(); + FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT(); #endif - Completer completer(this); - pVoid = &m_storage; - ::new (pVoid) T(); - atexit(cleanupFunc); // ignore failure (that's what the C runtime does, too) - completer.Succeed(); - } - return static_cast(pVoid); - } - - private: - INIT_ONCE m_initOnce; - alignas(T) BYTE m_storage[sizeof(T)]; - struct Completer - { - static_lazy* m_pSelf; - DWORD m_flags; - - explicit Completer(static_lazy* pSelf) WI_NOEXCEPT : m_pSelf(pSelf), m_flags(INIT_ONCE_INIT_FAILED) - { - } - void Succeed() WI_NOEXCEPT - { - m_flags = 0; - } - - ~Completer() WI_NOEXCEPT - { - if (m_flags == 0) - { - reinterpret_cast(&m_pSelf->m_storage)->Create(); + Completer completer(this); + pVoid = &m_storage; + ::new (pVoid) T(); + atexit(cleanupFunc); // ignore failure (that's what the C runtime does, too) + completer.Succeed(); } - ::InitOnceComplete(&m_pSelf->m_initOnce, m_flags, &m_pSelf->m_storage); + return static_cast(pVoid); } + + private: + INIT_ONCE m_initOnce; + alignas(T) BYTE m_storage[sizeof(T)]; + struct Completer + { + static_lazy *m_pSelf; + DWORD m_flags; + + explicit Completer(static_lazy *pSelf) WI_NOEXCEPT : m_pSelf(pSelf), m_flags(INIT_ONCE_INIT_FAILED) + { + } + void Succeed() WI_NOEXCEPT + { + m_flags = 0; + } + + ~Completer() WI_NOEXCEPT + { + if (m_flags == 0) + { + reinterpret_cast(&m_pSelf->m_storage)->Create(); + } + ::InitOnceComplete(&m_pSelf->m_initOnce, m_flags, &m_pSelf->m_storage); + } + }; }; - }; - // This class serves as a simple RAII wrapper around CallContextInfo. It presumes that - // the contextName parameter is always a static string, but copies or allocates the - // contextMessage as needed. + // This class serves as a simple RAII wrapper around CallContextInfo. It presumes that + // the contextName parameter is always a static string, but copies or allocates the + // contextMessage as needed. - class StoredCallContextInfo : public wil::CallContextInfo - { - public: - StoredCallContextInfo() WI_NOEXCEPT + class StoredCallContextInfo : public wil::CallContextInfo { - // Suppress '-Wnontrivial-memcall' with 'static_cast' - ::ZeroMemory(static_cast(this), sizeof(*this)); - } - - StoredCallContextInfo(StoredCallContextInfo&& other) WI_NOEXCEPT : StoredCallContextInfo() - { - operator=(wistd::move(other)); - } - - StoredCallContextInfo& operator=(StoredCallContextInfo&& other) WI_NOEXCEPT - { - contextId = other.contextId; - contextName = other.contextName; - ClearMessage(); - contextMessage = other.contextMessage; - other.contextMessage = nullptr; - m_ownsMessage = other.m_ownsMessage; - other.m_ownsMessage = false; - return *this; - } - - StoredCallContextInfo(StoredCallContextInfo const& other) WI_NOEXCEPT : m_ownsMessage(false) - { - contextId = other.contextId; - contextName = other.contextName; - if (other.m_ownsMessage) + public: + StoredCallContextInfo() WI_NOEXCEPT { - AssignMessage(other.contextMessage); + // Suppress '-Wnontrivial-memcall' with 'static_cast' + ::ZeroMemory(static_cast(this), sizeof(*this)); } - else + + StoredCallContextInfo(StoredCallContextInfo &&other) WI_NOEXCEPT : StoredCallContextInfo() { + operator=(wistd::move(other)); + } + + StoredCallContextInfo &operator=(StoredCallContextInfo &&other) WI_NOEXCEPT + { + contextId = other.contextId; + contextName = other.contextName; + ClearMessage(); contextMessage = other.contextMessage; + other.contextMessage = nullptr; + m_ownsMessage = other.m_ownsMessage; + other.m_ownsMessage = false; + return *this; } + + StoredCallContextInfo(StoredCallContextInfo const &other) WI_NOEXCEPT : m_ownsMessage(false) + { + contextId = other.contextId; + contextName = other.contextName; + if (other.m_ownsMessage) + { + AssignMessage(other.contextMessage); + } + else + { + contextMessage = other.contextMessage; + } + } + + StoredCallContextInfo(_In_opt_ PCSTR staticContextName) WI_NOEXCEPT : m_ownsMessage(false) + { + contextId = 0; + contextName = staticContextName; + contextMessage = nullptr; + } + + StoredCallContextInfo(PCSTR staticContextName, _Printf_format_string_ PCSTR formatString, + va_list argList) WI_NOEXCEPT : StoredCallContextInfo(staticContextName) + { + SetMessage(formatString, argList); + } + + void SetMessage(_Printf_format_string_ PCSTR formatString, va_list argList) + { + wchar_t loggingMessage[2048]; + PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); + ClearMessage(); + AssignMessage(loggingMessage); + } + + void SetMessage(_In_opt_ PCWSTR message) + { + ClearMessage(); + contextMessage = message; + } + + void SetMessageCopy(_In_opt_ PCWSTR message) + { + ClearMessage(); + if (message != nullptr) + { + AssignMessage(message); + } + } + + void ClearMessage() + { + if (m_ownsMessage) + { + WIL_FreeMemory(const_cast(contextMessage)); + m_ownsMessage = false; + } + contextMessage = nullptr; + } + + ~StoredCallContextInfo() + { + ClearMessage(); + } + + StoredCallContextInfo &operator=(StoredCallContextInfo const &) = delete; + + private: + void AssignMessage(PCWSTR message) + { + auto length = wcslen(message); + if (length > 0) + { + auto sizeBytes = (length + 1) * sizeof(wchar_t); + contextMessage = static_cast(WIL_AllocateMemory(sizeBytes)); + if (contextMessage != nullptr) + { + m_ownsMessage = true; + memcpy_s(const_cast(contextMessage), sizeBytes, message, sizeBytes); + } + } + } + + bool m_ownsMessage; + }; + + template void SetRelatedActivityId(TActivity &) + { } - StoredCallContextInfo(_In_opt_ PCSTR staticContextName) WI_NOEXCEPT : m_ownsMessage(false) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + template + void SetRelatedActivityId( + wil::ActivityBase &activity) + { + GUID capturedRelatedId; + EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, &capturedRelatedId); + activity.SetRelatedActivityId(capturedRelatedId); + } +#endif + + typedef wistd::integral_constant tag_start; + typedef wistd::integral_constant tag_start_cv; + } // namespace details + /// @endcond + + // This class acts as a simple RAII class returned by a call to ContinueOnCurrentThread() for an activity + // or by a call to WatchCurrentThread() on a provider. The result is meant to be a stack local variable + // whose scope controls the lifetime of an error watcher on the given thread. That error watcher re-directs + // errors occurrent within the object's lifetime to the associated provider or activity. + + class ActivityThreadWatcher + { + public: + ActivityThreadWatcher() WI_NOEXCEPT : m_callbackHolder(nullptr, nullptr, false) { - contextId = 0; - contextName = staticContextName; - contextMessage = nullptr; } - StoredCallContextInfo(PCSTR staticContextName, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - : StoredCallContextInfo(staticContextName) + ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, PCSTR staticContextName) WI_NOEXCEPT + : m_callContext(staticContextName), + m_callbackHolder(pCallback, &m_callContext) { - SetMessage(formatString, argList); } - void SetMessage(_Printf_format_string_ PCSTR formatString, va_list argList) + ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, PCSTR staticContextName, + _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + : ActivityThreadWatcher(pCallback, staticContextName) { - wchar_t loggingMessage[2048]; - PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - ClearMessage(); - AssignMessage(loggingMessage); + m_callContext.SetMessage(formatString, argList); + } + + // Uses the supplied StoredCallContextInfo rather than producing one itself + ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, + _In_ details::StoredCallContextInfo const &callContext) WI_NOEXCEPT + : m_callContext(callContext), + m_callbackHolder(pCallback, &m_callContext) + { + } + + ActivityThreadWatcher(ActivityThreadWatcher &&other) WI_NOEXCEPT + : m_callContext(wistd::move(other.m_callContext)), + m_callbackHolder(wistd::move(other.m_callbackHolder)) + { + m_callbackHolder.SetCallContext(&m_callContext); + } + + ActivityThreadWatcher(ActivityThreadWatcher const &) = delete; + ActivityThreadWatcher &operator=(ActivityThreadWatcher const &) = delete; + + void SetMessage(_Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + m_callContext.SetMessage(formatString, argList); + va_end(argList); } void SetMessage(_In_opt_ PCWSTR message) { - ClearMessage(); - contextMessage = message; + m_callContext.SetMessage(message); } void SetMessageCopy(_In_opt_ PCWSTR message) { - ClearMessage(); - if (message != nullptr) - { - AssignMessage(message); - } + m_callContext.SetMessageCopy(message); } - void ClearMessage() + private: + details::StoredCallContextInfo m_callContext; + details::ThreadFailureCallbackHolder m_callbackHolder; + }; + + // This is the base-class implementation of a TraceLogging class. TraceLogging classes are defined with + // BEGIN_TRACELOGGING_CLASS and automatically derive from this class + + enum class ErrorReportingType + { + None = 0, + Telemetry, + TraceLogging + }; + + class TraceLoggingProvider : public details::IFailureCallback + { + public: + // Only one instance of each of these derived classes should be created + TraceLoggingProvider(_In_ TraceLoggingProvider const &) = delete; + TraceLoggingProvider &operator=(TraceLoggingProvider const &) = delete; + void *operator new(size_t) = delete; + void *operator new[](size_t) = delete; + + protected: + // This can be overridden to provide specific initialization code for any individual provider. + // It will be ran once when the single static singleton instance of this class is created. + virtual void Initialize() WI_NOEXCEPT { - if (m_ownsMessage) - { - WIL_FreeMemory(const_cast(contextMessage)); - m_ownsMessage = false; - } - contextMessage = nullptr; } - ~StoredCallContextInfo() + // This method can be overridden by a provider to more tightly control what happens in the event + // of a failure in a CallContext activity, WatchCurrentThread() object, or attributed to a specific failure. + virtual void OnErrorReported(bool alreadyReported, FailureInfo const &failure) WI_NOEXCEPT { - ClearMessage(); - } - - StoredCallContextInfo& operator=(StoredCallContextInfo const&) = delete; - - private: - void AssignMessage(PCWSTR message) - { - auto length = wcslen(message); - if (length > 0) + if (!alreadyReported && WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) { - auto sizeBytes = (length + 1) * sizeof(wchar_t); - contextMessage = static_cast(WIL_AllocateMemory(sizeBytes)); - if (contextMessage != nullptr) + if (m_errorReportingType == ErrorReportingType::Telemetry) { - m_ownsMessage = true; - memcpy_s(const_cast(contextMessage), sizeBytes, message, sizeBytes); + ReportTelemetryFailure(failure); + } + else if (m_errorReportingType == ErrorReportingType::TraceLogging) + { + ReportTraceLoggingFailure(failure); } } } - bool m_ownsMessage; + public: + WI_NODISCARD TraceLoggingHProvider Provider_() const WI_NOEXCEPT + { + return m_providerHandle; + } + + protected: + TraceLoggingProvider() WI_NOEXCEPT + { + } + + virtual ~TraceLoggingProvider() WI_NOEXCEPT + { + if (m_ownsProviderHandle) + { + TraceLoggingUnregister(m_providerHandle); + } + } + + WI_NODISCARD bool IsEnabled_(UCHAR eventLevel /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, + ULONGLONG eventKeywords /* MICROSOFT_KEYWORD_XXX */) const WI_NOEXCEPT + { + return ((m_providerHandle != nullptr) && + TraceLoggingProviderEnabled(m_providerHandle, eventLevel, eventKeywords)) || + __TRACELOGGING_TEST_HOOK_SET_ENABLED; + } + + void SetErrorReportingType_(ErrorReportingType type) + { + m_errorReportingType = type; + } + + static bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT + { + static long volatile s_lastFailureSeen = -1; + auto wasSeen = (s_lastFailureSeen == failureId); + s_lastFailureSeen = failureId; + return wasSeen; + } + + void ReportTelemetryFailure(FailureInfo const &failure) WI_NOEXCEPT + { + __TRACELOGGING_TEST_HOOK_ERROR(failure); + TraceLoggingWrite(m_providerHandle, "FallbackError", + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + __RESULT_TELEMETRY_FAILURE_PARAMS(failure)); + } + + void ReportTraceLoggingFailure(FailureInfo const &failure) WI_NOEXCEPT + { + TraceLoggingWrite(m_providerHandle, "FallbackError", TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + __RESULT_TRACELOGGING_FAILURE_PARAMS(failure)); + } + + // Helper function for TraceLoggingError. + // It prints out a trace message for debug purposes. The message does not go into the telemetry. + void ReportTraceLoggingError(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + if (IsEnabled_(WINEVENT_LEVEL_ERROR, 0)) + { + wchar_t loggingMessage[2048]; + details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); + TraceLoggingWrite(m_providerHandle, "TraceLoggingError", TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); + } + } + + // Helper function for TraceLoggingInfo. + // It prints out a trace message for debug purposes. The message does not go into the telemetry. + void ReportTraceLoggingMessage(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + if (IsEnabled_(WINEVENT_LEVEL_VERBOSE, 0)) + { + wchar_t loggingMessage[2048]; + details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); + TraceLoggingWrite(m_providerHandle, "TraceLoggingInfo", TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); + } + } + + void Register(TraceLoggingHProvider const providerHandle, TLG_PENABLECALLBACK callback = nullptr) WI_NOEXCEPT + { + // taking over the lifetime and management of providerHandle + m_providerHandle = providerHandle; + m_ownsProviderHandle = true; + TraceLoggingRegisterEx(providerHandle, callback, nullptr); + InternalInitialize(); + } + + void AttachProvider(TraceLoggingHProvider const providerHandle) WI_NOEXCEPT + { + m_providerHandle = providerHandle; + m_ownsProviderHandle = false; + InternalInitialize(); + } + + private: + // IFailureCallback + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override + { + if (!WasAlreadyReportedToTelemetry(failure.failureId)) + { + OnErrorReported(false, failure); + } + return true; + } + + void InternalInitialize() + { + m_errorReportingType = ErrorReportingType::Telemetry; + Initialize(); + } + + TraceLoggingHProvider m_providerHandle{}; + bool m_ownsProviderHandle{}; + ErrorReportingType m_errorReportingType{}; }; - template - void SetRelatedActivityId(TActivity&) + template // helps TlgReflector understand that this is a wrapper type + class BasicActivity + : public _TlgActivityBase, keyword, level> { - } + using BaseTy = + _TlgActivityBase, keyword, level>; + friend BaseTy; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - template - void SetRelatedActivityId(wil::ActivityBase& activity) - { - GUID capturedRelatedId; - EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, &capturedRelatedId); - activity.SetRelatedActivityId(capturedRelatedId); - } -#endif - - typedef wistd::integral_constant tag_start; - typedef wistd::integral_constant tag_start_cv; -} // namespace details -/// @endcond - -// This class acts as a simple RAII class returned by a call to ContinueOnCurrentThread() for an activity -// or by a call to WatchCurrentThread() on a provider. The result is meant to be a stack local variable -// whose scope controls the lifetime of an error watcher on the given thread. That error watcher re-directs -// errors occurrent within the object's lifetime to the associated provider or activity. - -class ActivityThreadWatcher -{ -public: - ActivityThreadWatcher() WI_NOEXCEPT : m_callbackHolder(nullptr, nullptr, false) - { - } - - ActivityThreadWatcher(_In_ details::IFailureCallback* pCallback, PCSTR staticContextName) WI_NOEXCEPT - : m_callContext(staticContextName), - m_callbackHolder(pCallback, &m_callContext) - { - } - - ActivityThreadWatcher( - _In_ details::IFailureCallback* pCallback, PCSTR staticContextName, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - : ActivityThreadWatcher(pCallback, staticContextName) - { - m_callContext.SetMessage(formatString, argList); - } - - // Uses the supplied StoredCallContextInfo rather than producing one itself - ActivityThreadWatcher(_In_ details::IFailureCallback* pCallback, _In_ details::StoredCallContextInfo const& callContext) WI_NOEXCEPT - : m_callContext(callContext), - m_callbackHolder(pCallback, &m_callContext) - { - } - - ActivityThreadWatcher(ActivityThreadWatcher&& other) WI_NOEXCEPT : m_callContext(wistd::move(other.m_callContext)), - m_callbackHolder(wistd::move(other.m_callbackHolder)) - { - m_callbackHolder.SetCallContext(&m_callContext); - } - - ActivityThreadWatcher(ActivityThreadWatcher const&) = delete; - ActivityThreadWatcher& operator=(ActivityThreadWatcher const&) = delete; - - void SetMessage(_Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - m_callContext.SetMessage(formatString, argList); - va_end(argList); - } - - void SetMessage(_In_opt_ PCWSTR message) - { - m_callContext.SetMessage(message); - } - - void SetMessageCopy(_In_opt_ PCWSTR message) - { - m_callContext.SetMessageCopy(message); - } - -private: - details::StoredCallContextInfo m_callContext; - details::ThreadFailureCallbackHolder m_callbackHolder; -}; - -// This is the base-class implementation of a TraceLogging class. TraceLogging classes are defined with -// BEGIN_TRACELOGGING_CLASS and automatically derive from this class - -enum class ErrorReportingType -{ - None = 0, - Telemetry, - TraceLogging -}; - -class TraceLoggingProvider : public details::IFailureCallback -{ -public: - // Only one instance of each of these derived classes should be created - TraceLoggingProvider(_In_ TraceLoggingProvider const&) = delete; - TraceLoggingProvider& operator=(TraceLoggingProvider const&) = delete; - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - -protected: - // This can be overridden to provide specific initialization code for any individual provider. - // It will be ran once when the single static singleton instance of this class is created. - virtual void Initialize() WI_NOEXCEPT - { - } - - // This method can be overridden by a provider to more tightly control what happens in the event - // of a failure in a CallContext activity, WatchCurrentThread() object, or attributed to a specific failure. - virtual void OnErrorReported(bool alreadyReported, FailureInfo const& failure) WI_NOEXCEPT - { - if (!alreadyReported && WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) + void OnStarted() { - if (m_errorReportingType == ErrorReportingType::Telemetry) - { - ReportTelemetryFailure(failure); - } - else if (m_errorReportingType == ErrorReportingType::TraceLogging) - { - ReportTraceLoggingFailure(failure); - } } - } -public: - WI_NODISCARD TraceLoggingHProvider Provider_() const WI_NOEXCEPT - { - return m_providerHandle; - } - -protected: - TraceLoggingProvider() WI_NOEXCEPT - { - } - - virtual ~TraceLoggingProvider() WI_NOEXCEPT - { - if (m_ownsProviderHandle) + void OnStopped() { - TraceLoggingUnregister(m_providerHandle); } - } - WI_NODISCARD bool IsEnabled_( - UCHAR eventLevel /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, - ULONGLONG eventKeywords /* MICROSOFT_KEYWORD_XXX */) const WI_NOEXCEPT - { - return ((m_providerHandle != nullptr) && TraceLoggingProviderEnabled(m_providerHandle, eventLevel, eventKeywords)) || - __TRACELOGGING_TEST_HOOK_SET_ENABLED; - } - - void SetErrorReportingType_(ErrorReportingType type) - { - m_errorReportingType = type; - } - - static bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT - { - static long volatile s_lastFailureSeen = -1; - auto wasSeen = (s_lastFailureSeen == failureId); - s_lastFailureSeen = failureId; - return wasSeen; - } - - void ReportTelemetryFailure(FailureInfo const& failure) WI_NOEXCEPT - { - __TRACELOGGING_TEST_HOOK_ERROR(failure); - TraceLoggingWrite( - m_providerHandle, - "FallbackError", - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __RESULT_TELEMETRY_FAILURE_PARAMS(failure)); - } - - void ReportTraceLoggingFailure(FailureInfo const& failure) WI_NOEXCEPT - { - TraceLoggingWrite( - m_providerHandle, "FallbackError", TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __RESULT_TRACELOGGING_FAILURE_PARAMS(failure)); - } - - // Helper function for TraceLoggingError. - // It prints out a trace message for debug purposes. The message does not go into the telemetry. - void ReportTraceLoggingError(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - if (IsEnabled_(WINEVENT_LEVEL_ERROR, 0)) + public: + BasicActivity() { - wchar_t loggingMessage[2048]; - details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - TraceLoggingWrite( - m_providerHandle, - "TraceLoggingError", - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); } - } - // Helper function for TraceLoggingInfo. - // It prints out a trace message for debug purposes. The message does not go into the telemetry. - void ReportTraceLoggingMessage(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - if (IsEnabled_(WINEVENT_LEVEL_VERBOSE, 0)) + BasicActivity(BasicActivity &&rhs) : BaseTy(wistd::move(rhs)) { - wchar_t loggingMessage[2048]; - details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - TraceLoggingWrite( - m_providerHandle, - "TraceLoggingInfo", - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); } - } - void Register(TraceLoggingHProvider const providerHandle, TLG_PENABLECALLBACK callback = nullptr) WI_NOEXCEPT - { - // taking over the lifetime and management of providerHandle - m_providerHandle = providerHandle; - m_ownsProviderHandle = true; - TraceLoggingRegisterEx(providerHandle, callback, nullptr); - InternalInitialize(); - } - - void AttachProvider(TraceLoggingHProvider const providerHandle) WI_NOEXCEPT - { - m_providerHandle = providerHandle; - m_ownsProviderHandle = false; - InternalInitialize(); - } - -private: - // IFailureCallback - bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT override - { - if (!WasAlreadyReportedToTelemetry(failure.failureId)) + BasicActivity &operator=(BasicActivity &&rhs) { - OnErrorReported(false, failure); + BaseTy::operator=(wistd::move(rhs)); + return *this; } - return true; - } - void InternalInitialize() + /* + Returns a handle to the TraceLogging provider associated with this activity. + */ + WI_NODISCARD TraceLoggingHProvider Provider() const + { + return TraceLoggingType::Provider(); + } + + /* + Sets the related (parent) activity. + May only be called once. If used, must be called before starting the activity. + */ + template void SetRelatedActivity(_In_ const ActivityTy &relatedActivity) + { + this->SetRelatedId(*relatedActivity.Id()); + } + + /* + Sets the related (parent) activity. + May only be called once. If used, must be called before starting the activity. + */ + void SetRelatedActivityId(_In_ const GUID &relatedActivityId) + { + this->SetRelatedId(relatedActivityId); + } + + /* + Sets the related (parent) activity. + May only be called once. If used, must be called before starting the activity. + */ + void SetRelatedActivityId(_In_ const GUID *relatedActivityId) + { + __FAIL_FAST_IMMEDIATE_ASSERT__(relatedActivityId != NULL); + this->SetRelatedId(*relatedActivityId); + } + }; + + template // helps TlgReflector understand that this is a wrapper type + class BasicThreadActivity + : public _TlgActivityBase, keyword, + level> { - m_errorReportingType = ErrorReportingType::Telemetry; - Initialize(); - } + using BaseTy = + _TlgActivityBase, keyword, level>; + friend BaseTy; - TraceLoggingHProvider m_providerHandle{}; - bool m_ownsProviderHandle{}; - ErrorReportingType m_errorReportingType{}; -}; + void OnStarted() + { + this->PushThreadActivityId(); + } -template < - typename TraceLoggingType, - UINT64 keyword = 0, - UINT8 level = WINEVENT_LEVEL_VERBOSE, - typename TlgReflectorTag = _TlgReflectorTag_Param0IsProviderType> // helps TlgReflector understand that this is a wrapper type -class BasicActivity : public _TlgActivityBase, keyword, level> -{ - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; + void OnStopped() + { + this->PopThreadActivityId(); + } - void OnStarted() - { - } + public: + BasicThreadActivity() + { + } - void OnStopped() - { - } + BasicThreadActivity(BasicThreadActivity &&rhs) : BaseTy(wistd::move(rhs)) + { + } -public: - BasicActivity() - { - } + BasicThreadActivity &operator=(BasicThreadActivity &&rhs) + { + BaseTy::operator=(wistd::move(rhs)); + return *this; + } - BasicActivity(BasicActivity&& rhs) : BaseTy(wistd::move(rhs)) - { - } - - BasicActivity& operator=(BasicActivity&& rhs) - { - BaseTy::operator=(wistd::move(rhs)); - return *this; - } - - /* - Returns a handle to the TraceLogging provider associated with this activity. - */ - WI_NODISCARD TraceLoggingHProvider Provider() const - { - return TraceLoggingType::Provider(); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - template - void SetRelatedActivity(_In_ const ActivityTy& relatedActivity) - { - this->SetRelatedId(*relatedActivity.Id()); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - void SetRelatedActivityId(_In_ const GUID& relatedActivityId) - { - this->SetRelatedId(relatedActivityId); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - void SetRelatedActivityId(_In_ const GUID* relatedActivityId) - { - __FAIL_FAST_IMMEDIATE_ASSERT__(relatedActivityId != NULL); - this->SetRelatedId(*relatedActivityId); - } -}; - -template < - typename TraceLoggingType, - UINT64 keyword = 0, - UINT8 level = WINEVENT_LEVEL_VERBOSE, - typename TlgReflectorTag = _TlgReflectorTag_Param0IsProviderType> // helps TlgReflector understand that this is a wrapper type -class BasicThreadActivity - : public _TlgActivityBase, keyword, level> -{ - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; - - void OnStarted() - { - this->PushThreadActivityId(); - } - - void OnStopped() - { - this->PopThreadActivityId(); - } - -public: - BasicThreadActivity() - { - } - - BasicThreadActivity(BasicThreadActivity&& rhs) : BaseTy(wistd::move(rhs)) - { - } - - BasicThreadActivity& operator=(BasicThreadActivity&& rhs) - { - BaseTy::operator=(wistd::move(rhs)); - return *this; - } - - /* - Returns a handle to the TraceLogging provider associated with this activity. - */ - WI_NODISCARD TraceLoggingHProvider Provider() const - { - return TraceLoggingType::Provider(); - } -}; + /* + Returns a handle to the TraceLogging provider associated with this activity. + */ + WI_NODISCARD TraceLoggingHProvider Provider() const + { + return TraceLoggingType::Provider(); + } + }; /// @cond -#define __WI_TraceLoggingWriteTagged(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ - { \ - _tlgActivityDecl(activity) \ - TraceLoggingWriteActivity(TraceLoggingType::Provider(), (name), _tlgActivityRef(activity).Id(), NULL, ##__VA_ARGS__); \ - } \ - while (0) \ +#define __WI_TraceLoggingWriteTagged(activity, name, ...) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ + { \ + _tlgActivityDecl(activity) TraceLoggingWriteActivity(TraceLoggingType::Provider(), (name), \ + _tlgActivityRef(activity).Id(), NULL, ##__VA_ARGS__); \ + } \ + while (0) \ __pragma(warning(pop)) /// @endcond -// This is the ultimate base class implementation for all activities. Activity classes are defined with -// DEFINE_TRACELOGGING_ACTIVITY, DEFINE_CALLCONTEXT_ACTIVITY, DEFINE_TELEMETRY_ACTIVITY and others + // This is the ultimate base class implementation for all activities. Activity classes are defined with + // DEFINE_TRACELOGGING_ACTIVITY, DEFINE_CALLCONTEXT_ACTIVITY, DEFINE_TELEMETRY_ACTIVITY and others -template -class ActivityBase : public details::IFailureCallback -{ -public: - typedef ActivityTraceLoggingType TraceLoggingType; - - static UINT64 const Keyword = keyword; - static UINT8 const Level = level; - static UINT64 const PrivacyTag = privacyTag; - - ActivityBase(PCSTR contextName, bool shouldWatchErrors = false) WI_NOEXCEPT - : m_activityData(contextName), - m_pActivityData(&m_activityData), - m_callbackHolder(this, m_activityData.GetCallContext(), shouldWatchErrors) + template + class ActivityBase : public details::IFailureCallback { - } + public: + typedef ActivityTraceLoggingType TraceLoggingType; - ActivityBase(ActivityBase&& other, bool shouldWatchErrors) WI_NOEXCEPT - : m_activityData(wistd::move(other.m_activityData)), - m_sharedActivityData(wistd::move(other.m_sharedActivityData)), - m_callbackHolder(this, nullptr, shouldWatchErrors) - { - m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - other.m_pActivityData = &other.m_activityData; - if (other.m_callbackHolder.IsWatching()) + static UINT64 const Keyword = keyword; + static UINT8 const Level = level; + static UINT64 const PrivacyTag = privacyTag; + + ActivityBase(PCSTR contextName, bool shouldWatchErrors = false) WI_NOEXCEPT + : m_activityData(contextName), + m_pActivityData(&m_activityData), + m_callbackHolder(this, m_activityData.GetCallContext(), shouldWatchErrors) { - other.m_callbackHolder.StopWatching(); - } - } - - ActivityBase(ActivityBase&& other) WI_NOEXCEPT : ActivityBase(wistd::move(other), other.m_callbackHolder.IsWatching()) - { - } - - ActivityBase(ActivityBase const& other) WI_NOEXCEPT - : m_activityData(), - m_pActivityData(&m_activityData), - m_callbackHolder(this, nullptr, false) // false = do not automatically watch for failures - { - operator=(other); - } - - ActivityBase& operator=(ActivityBase&& other) WI_NOEXCEPT - { - m_activityData = wistd::move(other.m_activityData); - m_sharedActivityData = wistd::move(other.m_sharedActivityData); - m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - m_callbackHolder.SetWatching(other.m_callbackHolder.IsWatching()); - other.m_pActivityData = &other.m_activityData; - if (other.m_callbackHolder.IsWatching()) - { - other.m_callbackHolder.StopWatching(); - } - return *this; - } - - ActivityBase& operator=(ActivityBase const& other) WI_NOEXCEPT - { - if (m_callbackHolder.IsWatching()) - { - m_callbackHolder.StopWatching(); } - if (other.m_sharedActivityData) + ActivityBase(ActivityBase &&other, bool shouldWatchErrors) WI_NOEXCEPT + : m_activityData(wistd::move(other.m_activityData)), + m_sharedActivityData(wistd::move(other.m_sharedActivityData)), + m_callbackHolder(this, nullptr, shouldWatchErrors) { - m_pActivityData = other.m_pActivityData; - m_sharedActivityData = other.m_sharedActivityData; + m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; + m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); + other.m_pActivityData = &other.m_activityData; + if (other.m_callbackHolder.IsWatching()) + { + other.m_callbackHolder.StopWatching(); + } } - else if (m_sharedActivityData.create(wistd::move(other.m_activityData))) + + ActivityBase(ActivityBase &&other) WI_NOEXCEPT + : ActivityBase(wistd::move(other), other.m_callbackHolder.IsWatching()) { - // Locking should not be required as the first copy should always take place on the owning - // thread... - m_pActivityData = m_sharedActivityData.get(); - other.m_sharedActivityData = m_sharedActivityData; - other.m_pActivityData = m_pActivityData; - other.m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); } - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - return *this; - } - // These calls all result in setting a message to associate with any failures that might occur while - // running the activity. For example, you could associate a filename with a call context activity - // so that the file name is only reported if the activity fails with the failure. - - void SetMessage(_In_ _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - auto lock = LockExclusive(); - GetCallContext()->SetMessage(formatString, argList); - va_end(argList); - } - - void SetMessage(_In_opt_ PCWSTR message) - { - auto lock = LockExclusive(); - GetCallContext()->SetMessage(message); - } - - void SetMessageCopy(_In_opt_ PCWSTR message) - { - auto lock = LockExclusive(); - GetCallContext()->SetMessageCopy(message); - } - - // This call stops watching for errors on the thread that the activity was originally - // created on. Use it when moving the activity into a thread-agnostic class or moving - // an activity across threads. - - void IgnoreCurrentThread() WI_NOEXCEPT - { - if (m_callbackHolder.IsWatching()) + ActivityBase(ActivityBase const &other) WI_NOEXCEPT + : m_activityData(), + m_pActivityData(&m_activityData), + m_callbackHolder(this, nullptr, false) // false = do not automatically watch for failures { - m_callbackHolder.StopWatching(); + operator=(other); } - } - // Call this API to retrieve an RAII object to watch events on the current thread. The returned - // object should only be used on the stack. - - WI_NODISCARD ActivityThreadWatcher ContinueOnCurrentThread() WI_NOEXCEPT - { - if (IsRunning()) + ActivityBase &operator=(ActivityBase &&other) WI_NOEXCEPT { - return ActivityThreadWatcher(this, *m_pActivityData->GetCallContext()); + m_activityData = wistd::move(other.m_activityData); + m_sharedActivityData = wistd::move(other.m_sharedActivityData); + m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; + m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); + m_callbackHolder.SetWatching(other.m_callbackHolder.IsWatching()); + other.m_pActivityData = &other.m_activityData; + if (other.m_callbackHolder.IsWatching()) + { + other.m_callbackHolder.StopWatching(); + } + return *this; } - return ActivityThreadWatcher(); - } - // This is the 'default' Stop routine that accepts an HRESULT and completes the activity... + ActivityBase &operator=(ActivityBase const &other) WI_NOEXCEPT + { + if (m_callbackHolder.IsWatching()) + { + m_callbackHolder.StopWatching(); + } - void Stop(HRESULT hr = S_OK) WI_NOEXCEPT - { - bool stopActivity; - HRESULT hrLocal; + if (other.m_sharedActivityData) + { + m_pActivityData = other.m_pActivityData; + m_sharedActivityData = other.m_sharedActivityData; + } + else if (m_sharedActivityData.create(wistd::move(other.m_activityData))) + { + // Locking should not be required as the first copy should always take place on the owning + // thread... + m_pActivityData = m_sharedActivityData.get(); + other.m_sharedActivityData = m_sharedActivityData; + other.m_pActivityData = m_pActivityData; + other.m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); + } + m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); + return *this; + } + + // These calls all result in setting a message to associate with any failures that might occur while + // running the activity. For example, you could associate a filename with a call context activity + // so that the file name is only reported if the activity fails with the failure. + + void SetMessage(_In_ _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + auto lock = LockExclusive(); + GetCallContext()->SetMessage(formatString, argList); + va_end(argList); + } + + void SetMessage(_In_opt_ PCWSTR message) { auto lock = LockExclusive(); - stopActivity = m_pActivityData->SetStopResult(hr, &hrLocal); + GetCallContext()->SetMessage(message); } - if (stopActivity) + + void SetMessageCopy(_In_opt_ PCWSTR message) { - ReportStopActivity(hrLocal); + auto lock = LockExclusive(); + GetCallContext()->SetMessageCopy(message); } - else + + // This call stops watching for errors on the thread that the activity was originally + // created on. Use it when moving the activity into a thread-agnostic class or moving + // an activity across threads. + + void IgnoreCurrentThread() WI_NOEXCEPT { - __WI_TraceLoggingWriteTagged( - *this, - "ActivityIntermediateStop", - TraceLoggingKeyword(Keyword), - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - __ACTIVITY_STOP_PARAMS(hr)); + if (m_callbackHolder.IsWatching()) + { + m_callbackHolder.StopWatching(); + } } - IgnoreCurrentThread(); - } - // IFailureCallback + // Call this API to retrieve an RAII object to watch events on the current thread. The returned + // object should only be used on the stack. - bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT override - { - // We always report errors to the ETW stream, but we hold-back the telemetry keyword if we've already reported this error - // to this particular telemetry provider. - - __TRACELOGGING_TEST_HOOK_ACTIVITY_ERROR(failure); - - if (WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) + WI_NODISCARD ActivityThreadWatcher ContinueOnCurrentThread() WI_NOEXCEPT { + if (IsRunning()) + { + return ActivityThreadWatcher(this, *m_pActivityData->GetCallContext()); + } + return ActivityThreadWatcher(); + } + + // This is the 'default' Stop routine that accepts an HRESULT and completes the activity... + + void Stop(HRESULT hr = S_OK) WI_NOEXCEPT + { + bool stopActivity; + HRESULT hrLocal; + { + auto lock = LockExclusive(); + stopActivity = m_pActivityData->SetStopResult(hr, &hrLocal); + } + if (stopActivity) + { + ReportStopActivity(hrLocal); + } + else + { + __WI_TraceLoggingWriteTagged(*this, "ActivityIntermediateStop", TraceLoggingKeyword(Keyword), + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), + __ACTIVITY_STOP_PARAMS(hr)); + } + IgnoreCurrentThread(); + } + + // IFailureCallback + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override + { + // We always report errors to the ETW stream, but we hold-back the telemetry keyword if we've already + // reported this error to this particular telemetry provider. + + __TRACELOGGING_TEST_HOOK_ACTIVITY_ERROR(failure); + + if (WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) + { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" #endif #pragma warning(push) #pragma warning(disable : 6319) - if (false, WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure) && !WasAlreadyReportedToTelemetry(failure.failureId)) - { - __WI_TraceLoggingWriteTagged( - *this, - "ActivityError", - TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure)); - } - else if (false, WI_IsFlagSet(options, ActivityOptions::TraceLoggingOnFailure)) - { - __WI_TraceLoggingWriteTagged( - *this, - "ActivityError", - TraceLoggingKeyword(0), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); - } - else - { - __WI_TraceLoggingWriteTagged( - *this, - "ActivityError", - TraceLoggingKeyword(Keyword), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); - } + if (false, WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure) && + !WasAlreadyReportedToTelemetry(failure.failureId)) + { + __WI_TraceLoggingWriteTagged( + *this, "ActivityError", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure)); + } + else if (false, WI_IsFlagSet(options, ActivityOptions::TraceLoggingOnFailure)) + { + __WI_TraceLoggingWriteTagged(*this, "ActivityError", TraceLoggingKeyword(0), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); + } + else + { + __WI_TraceLoggingWriteTagged(*this, "ActivityError", TraceLoggingKeyword(Keyword), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); + } #pragma warning(pop) #ifdef __clang__ #pragma clang diagnostic pop #endif - } - - auto lock = LockExclusive(); - m_pActivityData->NotifyFailure(failure); - return true; - } - - // This is the base TraceLoggingActivity<> contract... we implement it so that this class - // can be used by all of the activity macros and we re-route the request as needed. - // - // The contract required by the TraceLogging Activity macros is: - // - activity.Keyword // compile-time constant - // - activity.Level // compile-time constant - // - activity.PrivacyTag // compile-time constant - // - activity.Provider() - // - activity.Id() - // - activity.zInternalRelatedId() - // - activity.zInternalStart() - // - activity.zInternalStop() - // In addition, for TlgReflector to work correctly, it must be possible for - // TlgReflector to statically map from typeof(activity) to hProvider. - - WI_NODISCARD GUID const* zInternalRelatedId() const WI_NOEXCEPT - { - return m_pActivityData->zInternalRelatedId(); - } - - void zInternalStart() WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->zInternalStart(); - } - - void zInternalStop() WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->zInternalStop(); - } - - static TraceLoggingHProvider Provider() WI_NOEXCEPT - { - return ActivityTraceLoggingType::Provider(); - } - - WI_NODISCARD GUID const* Id() const WI_NOEXCEPT - { - return m_pActivityData->Id(); - } - - WI_NODISCARD GUID const* providerGuid() const WI_NOEXCEPT - { - return m_pActivityData->providerGuid(); - } - - template - void SetRelatedActivity(OtherTy const& relatedActivity) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(relatedActivity.Id()); - } - - void SetRelatedActivityId(_In_ const GUID& relatedActivityId) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(&relatedActivityId); - } - - void SetRelatedActivityId(_In_ const GUID* relatedActivityId) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(relatedActivityId); - } - - WI_NODISCARD inline bool IsRunning() const WI_NOEXCEPT - { - return m_pActivityData->NeedsStopped(); - } - -protected: - virtual void StopActivity() WI_NOEXCEPT = 0; - virtual bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT = 0; - - void EnsureWatchingCurrentThread() - { - if (!m_callbackHolder.IsWatching()) - { - m_callbackHolder.StartWatching(); - } - } - - void SetStopResult(HRESULT hr, _Out_opt_ HRESULT* phr = nullptr) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetStopResult(hr, phr); - } - - void IncrementExpectedStopCount() WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->IncrementExpectedStopCount(); - } - - // Locking should not be required on these accessors as we only use this at reporting (which will only happen from - // the final stop) - - FailureInfo const* GetFailureInfo() WI_NOEXCEPT - { - return m_pActivityData->GetFailureInfo(); - } - - WI_NODISCARD inline HRESULT GetResult() const WI_NOEXCEPT - { - return m_pActivityData->GetResult(); - } - - WI_NODISCARD details::StoredCallContextInfo* GetCallContext() const WI_NOEXCEPT - { - return m_pActivityData->GetCallContext(); - } - - // Think of this routine as the destructor -- since we need to call virtual derived methods, we can't use it as - // a destructor without a pure virtual method call, so we have the derived class call it in its destructor... - - void Destroy() WI_NOEXCEPT - { - bool fStop = true; - if (m_sharedActivityData) - { - // The lock unifies the 'unique()' check and the 'reset()' of any non-unique activity so that we - // can positively identify the final release of the internal data + } auto lock = LockExclusive(); - if (!m_sharedActivityData.unique()) + m_pActivityData->NotifyFailure(failure); + return true; + } + + // This is the base TraceLoggingActivity<> contract... we implement it so that this class + // can be used by all of the activity macros and we re-route the request as needed. + // + // The contract required by the TraceLogging Activity macros is: + // - activity.Keyword // compile-time constant + // - activity.Level // compile-time constant + // - activity.PrivacyTag // compile-time constant + // - activity.Provider() + // - activity.Id() + // - activity.zInternalRelatedId() + // - activity.zInternalStart() + // - activity.zInternalStop() + // In addition, for TlgReflector to work correctly, it must be possible for + // TlgReflector to statically map from typeof(activity) to hProvider. + + WI_NODISCARD GUID const *zInternalRelatedId() const WI_NOEXCEPT + { + return m_pActivityData->zInternalRelatedId(); + } + + void zInternalStart() WI_NOEXCEPT + { + auto lock = LockExclusive(); + m_pActivityData->zInternalStart(); + } + + void zInternalStop() WI_NOEXCEPT + { + auto lock = LockExclusive(); + m_pActivityData->zInternalStop(); + } + + static TraceLoggingHProvider Provider() WI_NOEXCEPT + { + return ActivityTraceLoggingType::Provider(); + } + + WI_NODISCARD GUID const *Id() const WI_NOEXCEPT + { + return m_pActivityData->Id(); + } + + WI_NODISCARD GUID const *providerGuid() const WI_NOEXCEPT + { + return m_pActivityData->providerGuid(); + } + + template void SetRelatedActivity(OtherTy const &relatedActivity) WI_NOEXCEPT + { + auto lock = LockExclusive(); + m_pActivityData->SetRelatedActivityId(relatedActivity.Id()); + } + + void SetRelatedActivityId(_In_ const GUID &relatedActivityId) WI_NOEXCEPT + { + auto lock = LockExclusive(); + m_pActivityData->SetRelatedActivityId(&relatedActivityId); + } + + void SetRelatedActivityId(_In_ const GUID *relatedActivityId) WI_NOEXCEPT + { + auto lock = LockExclusive(); + m_pActivityData->SetRelatedActivityId(relatedActivityId); + } + + WI_NODISCARD inline bool IsRunning() const WI_NOEXCEPT + { + return m_pActivityData->NeedsStopped(); + } + + protected: + virtual void StopActivity() WI_NOEXCEPT = 0; + virtual bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT = 0; + + void EnsureWatchingCurrentThread() + { + if (!m_callbackHolder.IsWatching()) { - fStop = false; - m_sharedActivityData.reset(); + m_callbackHolder.StartWatching(); } } - if (fStop && m_pActivityData->NeedsStopped()) + void SetStopResult(HRESULT hr, _Out_opt_ HRESULT *phr = nullptr) WI_NOEXCEPT { - ReportStopActivity(m_pActivityData->SetUnhandledException()); - } - } - -private: - void ReportStopActivity(HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr) && - WI_AreAllFlagsClear(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | MICROSOFT_KEYWORD_CRITICAL_DATA)) && - WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure)) - { - wil::FailureInfo const* pFailure = GetFailureInfo(); - if (pFailure != nullptr) - { - __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(pFailure, pFailure->hr); - auto& failure = *pFailure; - __WI_TraceLoggingWriteTagged( - *this, - "ActivityFailure", - TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure)); - } - else - { - __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(nullptr, hr); - __WI_TraceLoggingWriteTagged( - *this, - "ActivityFailure", - TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_FAILURE_TELEMETRY_PARAMS( - hr, m_pActivityData->GetCallContext()->contextName, m_pActivityData->GetCallContext()->contextMessage)); - } - } - - StopActivity(); - } - - rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT - { - // We only need to lock when we're sharing.... - return (m_sharedActivityData ? m_sharedActivityData->LockExclusive() : rwlock_release_exclusive_scope_exit()); - } - - template - class ActivityData : public _TlgActivityBase, keyword, level> - { - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; - void OnStarted() - { - } - void OnStopped() - { - } - - // SFINAE dispatching on presence of ActivityTraceLoggingTypeOther::CreateActivityId(_Out_ GUID& childActivityId, _In_opt_ const GUID* relatedActivityId) - template - auto CreateActivityIdByProviderType(int, _Out_ GUID& childActivityId) - -> decltype(ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()), (void)0) - { - ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()); - } - - template - auto CreateActivityIdByProviderType(long, _Out_ GUID& childActivityId) -> void - { - EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &childActivityId); - } - - void CreateActivityId(_Out_ GUID& childActivityId) - { - CreateActivityIdByProviderType(0, childActivityId); - } - - public: - ActivityData(_In_opt_ PCSTR contextName = nullptr) WI_NOEXCEPT : BaseTy(), - m_callContext(contextName), - m_result(S_OK), - m_stopCountExpected(1) - { - } - - ActivityData(ActivityData&& other) WI_NOEXCEPT : BaseTy(wistd::move(other)), - m_callContext(wistd::move(other.m_callContext)), - m_result(other.m_result), - m_failure(wistd::move(other.m_failure)), - m_stopCountExpected(other.m_stopCountExpected) - { - } - - ActivityData& operator=(ActivityData&& other) WI_NOEXCEPT - { - BaseTy::operator=(wistd::move(other)); - m_callContext = wistd::move(other.m_callContext); - m_result = other.m_result; - m_failure = wistd::move(other.m_failure); - m_stopCountExpected = other.m_stopCountExpected; - return *this; - } - - ActivityData(ActivityData const& other) = delete; - ActivityData& operator=(ActivityData const& other) = delete; - - // returns true if the event was reported to telemetry - void NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT - { - if ((failure.hr != m_failure.GetFailureInfo().hr) && // don't replace with the same error (likely propagation up the stack) - ((failure.hr != m_result) || - SUCCEEDED(m_result))) // don't replace if we've already got the current explicitly supplied failure code - { - m_failure.SetFailureInfo(failure); - } - } - - rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT - { - return m_lock.lock_exclusive(); - } - - static TraceLoggingHProvider Provider() - { - return ActivityTraceLoggingTypeOther::Provider(); - } - - WI_NODISCARD bool NeedsStopped() const WI_NOEXCEPT - { - return BaseTy::IsStarted(); - } - - void SetRelatedActivityId(const GUID* relatedId) - { - this->SetRelatedId(*relatedId); - } - - bool SetStopResult(HRESULT hr, _Out_opt_ HRESULT* phr) WI_NOEXCEPT - { - // We must be expecting at least one Stop -- otherwise the caller is calling Stop() more times - // than it can (normally once, or +1 for each call to Split()) - __FAIL_FAST_IMMEDIATE_ASSERT__(m_stopCountExpected >= 1); - if (SUCCEEDED(m_result)) - { - m_result = hr; - } - if (phr != nullptr) - { - *phr = m_result; - } - return ((--m_stopCountExpected) == 0); - } - - HRESULT SetUnhandledException() WI_NOEXCEPT - { - HRESULT hr = m_failure.GetFailureInfo().hr; - SetStopResult(FAILED(hr) ? hr : HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), &hr); - return hr; + auto lock = LockExclusive(); + m_pActivityData->SetStopResult(hr, phr); } void IncrementExpectedStopCount() WI_NOEXCEPT { - m_stopCountExpected++; + auto lock = LockExclusive(); + m_pActivityData->IncrementExpectedStopCount(); } - WI_NODISCARD FailureInfo const* GetFailureInfo() const WI_NOEXCEPT + // Locking should not be required on these accessors as we only use this at reporting (which will only happen + // from the final stop) + + FailureInfo const *GetFailureInfo() WI_NOEXCEPT { - return (FAILED(m_result) && (m_result == m_failure.GetFailureInfo().hr)) ? &m_failure.GetFailureInfo() : nullptr; + return m_pActivityData->GetFailureInfo(); } WI_NODISCARD inline HRESULT GetResult() const WI_NOEXCEPT { - return m_result; + return m_pActivityData->GetResult(); } - details::StoredCallContextInfo* GetCallContext() WI_NOEXCEPT + WI_NODISCARD details::StoredCallContextInfo *GetCallContext() const WI_NOEXCEPT { - return &m_callContext; + return m_pActivityData->GetCallContext(); } - private: - details::StoredCallContextInfo m_callContext; - HRESULT m_result; - StoredFailureInfo m_failure; - int m_stopCountExpected; - wil::srwlock m_lock; - }; + // Think of this routine as the destructor -- since we need to call virtual derived methods, we can't use it as + // a destructor without a pure virtual method call, so we have the derived class call it in its destructor... - mutable ActivityData m_activityData; - mutable ActivityData* m_pActivityData; - mutable details::shared_object> m_sharedActivityData; - mutable details::ThreadFailureCallbackHolder m_callbackHolder; -}; + void Destroy() WI_NOEXCEPT + { + bool fStop = true; + if (m_sharedActivityData) + { + // The lock unifies the 'unique()' check and the 'reset()' of any non-unique activity so that we + // can positively identify the final release of the internal data + + auto lock = LockExclusive(); + if (!m_sharedActivityData.unique()) + { + fStop = false; + m_sharedActivityData.reset(); + } + } + + if (fStop && m_pActivityData->NeedsStopped()) + { + ReportStopActivity(m_pActivityData->SetUnhandledException()); + } + } + + private: + void ReportStopActivity(HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr) && + WI_AreAllFlagsClear(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | + MICROSOFT_KEYWORD_CRITICAL_DATA)) && + WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure)) + { + wil::FailureInfo const *pFailure = GetFailureInfo(); + if (pFailure != nullptr) + { + __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(pFailure, pFailure->hr); + auto &failure = *pFailure; + __WI_TraceLoggingWriteTagged( + *this, "ActivityFailure", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure)); + } + else + { + __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(nullptr, hr); + __WI_TraceLoggingWriteTagged( + *this, "ActivityFailure", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + __ACTIVITY_FAILURE_TELEMETRY_PARAMS(hr, m_pActivityData->GetCallContext()->contextName, + m_pActivityData->GetCallContext()->contextMessage)); + } + } + + StopActivity(); + } + + rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT + { + // We only need to lock when we're sharing.... + return (m_sharedActivityData ? m_sharedActivityData->LockExclusive() + : rwlock_release_exclusive_scope_exit()); + } + + template + class ActivityData + : public _TlgActivityBase, keyword, level> + { + using BaseTy = + _TlgActivityBase, keyword, level>; + friend BaseTy; + void OnStarted() + { + } + void OnStopped() + { + } + + // SFINAE dispatching on presence of ActivityTraceLoggingTypeOther::CreateActivityId(_Out_ GUID& + // childActivityId, _In_opt_ const GUID* relatedActivityId) + template + auto CreateActivityIdByProviderType(int, _Out_ GUID &childActivityId) + -> decltype(ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()), (void)0) + { + ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()); + } + + template + auto CreateActivityIdByProviderType(long, _Out_ GUID &childActivityId) -> void + { + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &childActivityId); + } + + void CreateActivityId(_Out_ GUID &childActivityId) + { + CreateActivityIdByProviderType(0, childActivityId); + } + + public: + ActivityData(_In_opt_ PCSTR contextName = nullptr) WI_NOEXCEPT : BaseTy(), + m_callContext(contextName), + m_result(S_OK), + m_stopCountExpected(1) + { + } + + ActivityData(ActivityData &&other) WI_NOEXCEPT : BaseTy(wistd::move(other)), + m_callContext(wistd::move(other.m_callContext)), + m_result(other.m_result), + m_failure(wistd::move(other.m_failure)), + m_stopCountExpected(other.m_stopCountExpected) + { + } + + ActivityData &operator=(ActivityData &&other) WI_NOEXCEPT + { + BaseTy::operator=(wistd::move(other)); + m_callContext = wistd::move(other.m_callContext); + m_result = other.m_result; + m_failure = wistd::move(other.m_failure); + m_stopCountExpected = other.m_stopCountExpected; + return *this; + } + + ActivityData(ActivityData const &other) = delete; + ActivityData &operator=(ActivityData const &other) = delete; + + // returns true if the event was reported to telemetry + void NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT + { + if ((failure.hr != m_failure.GetFailureInfo() + .hr) && // don't replace with the same error (likely propagation up the stack) + ((failure.hr != m_result) || + SUCCEEDED( + m_result))) // don't replace if we've already got the current explicitly supplied failure code + { + m_failure.SetFailureInfo(failure); + } + } + + rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT + { + return m_lock.lock_exclusive(); + } + + static TraceLoggingHProvider Provider() + { + return ActivityTraceLoggingTypeOther::Provider(); + } + + WI_NODISCARD bool NeedsStopped() const WI_NOEXCEPT + { + return BaseTy::IsStarted(); + } + + void SetRelatedActivityId(const GUID *relatedId) + { + this->SetRelatedId(*relatedId); + } + + bool SetStopResult(HRESULT hr, _Out_opt_ HRESULT *phr) WI_NOEXCEPT + { + // We must be expecting at least one Stop -- otherwise the caller is calling Stop() more times + // than it can (normally once, or +1 for each call to Split()) + __FAIL_FAST_IMMEDIATE_ASSERT__(m_stopCountExpected >= 1); + if (SUCCEEDED(m_result)) + { + m_result = hr; + } + if (phr != nullptr) + { + *phr = m_result; + } + return ((--m_stopCountExpected) == 0); + } + + HRESULT SetUnhandledException() WI_NOEXCEPT + { + HRESULT hr = m_failure.GetFailureInfo().hr; + SetStopResult(FAILED(hr) ? hr : HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), &hr); + return hr; + } + + void IncrementExpectedStopCount() WI_NOEXCEPT + { + m_stopCountExpected++; + } + + WI_NODISCARD FailureInfo const *GetFailureInfo() const WI_NOEXCEPT + { + return (FAILED(m_result) && (m_result == m_failure.GetFailureInfo().hr)) ? &m_failure.GetFailureInfo() + : nullptr; + } + + WI_NODISCARD inline HRESULT GetResult() const WI_NOEXCEPT + { + return m_result; + } + + details::StoredCallContextInfo *GetCallContext() WI_NOEXCEPT + { + return &m_callContext; + } + + private: + details::StoredCallContextInfo m_callContext; + HRESULT m_result; + StoredFailureInfo m_failure; + int m_stopCountExpected; + wil::srwlock m_lock; + }; + + mutable ActivityData m_activityData; + mutable ActivityData *m_pActivityData; + mutable details::shared_object> m_sharedActivityData; + mutable details::ThreadFailureCallbackHolder m_callbackHolder; + }; } // namespace wil // Internal MACRO implementation of Activities. // Do NOT use these macros directly. /// @cond -#define __WI_TraceLoggingWriteStart(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ - { \ - _tlgActivityDecl(activity); \ - using _tlg_Activity_t = wistd::remove_reference_t; \ - static constexpr const UINT64 _tlgActivity_Keyword = _tlg_Activity_t::Keyword; \ - static constexpr const UINT8 _tlgActivity_Level = _tlg_Activity_t::Level; \ - static constexpr const UINT64 _tlgActivityPrivacyTag = _tlg_Activity_t::PrivacyTag; \ - static_assert( \ - _tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, ##__VA_ARGS__)), \ - "Do not use TraceLoggingKeyword in TraceLoggingWriteStart. Keywords for START events are " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - static_assert( \ - _tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, ##__VA_ARGS__)), \ - "Do not use TraceLoggingLevel in TraceLoggingWriteStart. The Level for START events is " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - _tlgActivityRef(activity).zInternalStart(); \ - TraceLoggingWriteActivity( \ - TraceLoggingType::Provider(), \ - (name), \ - _tlgActivityRef(activity).Id(), \ - _tlgActivityRef(activity).zInternalRelatedId(), \ - TraceLoggingOpcode(1 /* WINEVENT_OPCODE_START */), \ - TraceLoggingKeyword(_tlgActivity_Keyword), \ - TraceLoggingLevel(_tlgActivity_Level), \ - TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ - TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"), \ - ##__VA_ARGS__); \ - } \ - while (0) \ +#define __WI_TraceLoggingWriteStart(activity, name, ...) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ + { \ + _tlgActivityDecl(activity); \ + using _tlg_Activity_t = wistd::remove_reference_t; \ + static constexpr const UINT64 _tlgActivity_Keyword = _tlg_Activity_t::Keyword; \ + static constexpr const UINT8 _tlgActivity_Level = _tlg_Activity_t::Level; \ + static constexpr const UINT64 _tlgActivityPrivacyTag = _tlg_Activity_t::PrivacyTag; \ + static_assert(_tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, ##__VA_ARGS__)), \ + "Do not use TraceLoggingKeyword in TraceLoggingWriteStart. Keywords for START events are " \ + "specified in the activity type, e.g. TraceLoggingActivity."); \ + static_assert(_tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, ##__VA_ARGS__)), \ + "Do not use TraceLoggingLevel in TraceLoggingWriteStart. The Level for START events is " \ + "specified in the activity type, e.g. TraceLoggingActivity."); \ + _tlgActivityRef(activity).zInternalStart(); \ + TraceLoggingWriteActivity(TraceLoggingType::Provider(), (name), _tlgActivityRef(activity).Id(), \ + _tlgActivityRef(activity).zInternalRelatedId(), \ + TraceLoggingOpcode(1 /* WINEVENT_OPCODE_START */), \ + TraceLoggingKeyword(_tlgActivity_Keyword), TraceLoggingLevel(_tlgActivity_Level), \ + TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ + TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"), ##__VA_ARGS__); \ + } \ + while (0) \ __pragma(warning(pop)) -#define __WRITE_ACTIVITY_START(EventId, ...) \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_START(); \ - __WI_TraceLoggingWriteStart(*this, #EventId, __ACTIVITY_START_PARAMS(), ##__VA_ARGS__); \ +#define __WRITE_ACTIVITY_START(EventId, ...) \ + __TRACELOGGING_TEST_HOOK_ACTIVITY_START(); \ + __WI_TraceLoggingWriteStart(*this, #EventId, __ACTIVITY_START_PARAMS(), ##__VA_ARGS__); \ EnsureWatchingCurrentThread() -#define __WI_TraceLoggingWriteStop(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ - { \ - _tlgActivityDecl(activity); \ - using _tlg_Activity_t = wistd::remove_reference_t; \ - static constexpr const UINT64 _tlgActivity_Keyword = _tlg_Activity_t::Keyword; \ - static constexpr const UINT8 _tlgActivity_Level = _tlg_Activity_t::Level; \ - static constexpr const UINT64 _tlgActivityPrivacyTag = _tlg_Activity_t::PrivacyTag; \ - static_assert( \ - _tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, ##__VA_ARGS__)), \ - "Do not use TraceLoggingKeyword in TraceLoggingWriteStop. Keywords for STOP events are " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - static_assert( \ - _tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, ##__VA_ARGS__)), \ - "Do not use TraceLoggingLevel in TraceLoggingWriteStop. The Level for STOP events is " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - _tlgActivityRef(activity).zInternalStop(); \ - TraceLoggingWriteActivity( \ - TraceLoggingType::Provider(), \ - (name), \ - _tlgActivityRef(activity).Id(), \ - NULL, \ - TraceLoggingOpcode(2 /* WINEVENT_OPCODE_STOP */), \ - TraceLoggingKeyword(_tlgActivity_Keyword), \ - TraceLoggingLevel(_tlgActivity_Level), \ - TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ - TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"), \ - ##__VA_ARGS__); \ - } \ - while (0) \ +#define __WI_TraceLoggingWriteStop(activity, name, ...) \ + __pragma(warning(push)) __pragma(warning(disable : 4127)) do \ + { \ + _tlgActivityDecl(activity); \ + using _tlg_Activity_t = wistd::remove_reference_t; \ + static constexpr const UINT64 _tlgActivity_Keyword = _tlg_Activity_t::Keyword; \ + static constexpr const UINT8 _tlgActivity_Level = _tlg_Activity_t::Level; \ + static constexpr const UINT64 _tlgActivityPrivacyTag = _tlg_Activity_t::PrivacyTag; \ + static_assert(_tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, ##__VA_ARGS__)), \ + "Do not use TraceLoggingKeyword in TraceLoggingWriteStop. Keywords for STOP events are " \ + "specified in the activity type, e.g. TraceLoggingActivity."); \ + static_assert(_tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, ##__VA_ARGS__)), \ + "Do not use TraceLoggingLevel in TraceLoggingWriteStop. The Level for STOP events is " \ + "specified in the activity type, e.g. TraceLoggingActivity."); \ + _tlgActivityRef(activity).zInternalStop(); \ + TraceLoggingWriteActivity(TraceLoggingType::Provider(), (name), _tlgActivityRef(activity).Id(), NULL, \ + TraceLoggingOpcode(2 /* WINEVENT_OPCODE_STOP */), \ + TraceLoggingKeyword(_tlgActivity_Keyword), TraceLoggingLevel(_tlgActivity_Level), \ + TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ + TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"), ##__VA_ARGS__); \ + } \ + while (0) \ __pragma(warning(pop)) -#define __WRITE_ACTIVITY_STOP(EventId, ...) \ - wil::FailureInfo const* pFailure = GetFailureInfo(); \ - if (pFailure != nullptr) \ - { \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(pFailure, pFailure->hr); \ - auto& failure = *pFailure; \ - if (false, WI_IsAnyFlagSet(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | MICROSOFT_KEYWORD_CRITICAL_DATA))) \ - { \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure), ##__VA_ARGS__); \ - } \ - else \ - { \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure), ##__VA_ARGS__); \ - } \ - } \ - else \ - { \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(nullptr, GetResult()); \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_PARAMS(GetResult()), ##__VA_ARGS__); \ - } \ +#define __WRITE_ACTIVITY_STOP(EventId, ...) \ + wil::FailureInfo const *pFailure = GetFailureInfo(); \ + if (pFailure != nullptr) \ + { \ + __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(pFailure, pFailure->hr); \ + auto &failure = *pFailure; \ + if (false, WI_IsAnyFlagSet(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | \ + MICROSOFT_KEYWORD_CRITICAL_DATA))) \ + { \ + __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure), \ + ##__VA_ARGS__); \ + } \ + else \ + { \ + __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure), \ + ##__VA_ARGS__); \ + } \ + } \ + else \ + { \ + __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(nullptr, GetResult()); \ + __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_PARAMS(GetResult()), ##__VA_ARGS__); \ + } \ IgnoreCurrentThread(); // optional params are: KeyWord, Level, PrivacyTags, Options -#define __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, ...) \ - class ActivityClassName final : public wil::ActivityBase \ - { \ - protected: \ - void StopActivity() WI_NOEXCEPT override \ - { \ - __WRITE_ACTIVITY_STOP(ActivityClassName); \ - } \ - bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT override \ - { \ - return TraceLoggingType::WasAlreadyReportedToTelemetry(failureId); \ - } \ -\ - public: \ - static bool IsEnabled() WI_NOEXCEPT \ - { \ - return TraceLoggingType::IsEnabled(); \ - } \ - ~ActivityClassName() WI_NOEXCEPT \ - { \ - ActivityBase::Destroy(); \ - } \ - ActivityClassName(ActivityClassName const& other) WI_NOEXCEPT : ActivityBase(other) \ - { \ - } \ - ActivityClassName(ActivityClassName&& other) WI_NOEXCEPT : ActivityBase(wistd::move(other)) \ - { \ - } \ - ActivityClassName(ActivityClassName&& other, bool shouldWatchErrors) WI_NOEXCEPT \ - : ActivityBase(wistd::move(other), shouldWatchErrors) \ - { \ - } \ - ActivityClassName& operator=(ActivityClassName const& other) WI_NOEXCEPT \ - { \ - ActivityBase::operator=(other); \ - return *this; \ - } \ - ActivityClassName& operator=(ActivityClassName&& other) WI_NOEXCEPT \ - { \ - auto localActivity(wistd::move(*this)); \ - ActivityBase::operator=(wistd::move(other)); \ - return *this; \ - } \ - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT \ - { \ - return IsRunning(); \ - } \ - void StopWithResult(HRESULT hr) \ - { \ - ActivityBase::Stop(hr); \ - } \ - template \ - void StopWithResult(HRESULT hr, TArgs&&... args) \ - { \ - SetStopResult(hr); \ - Stop(wistd::forward(args)...); \ - } \ - void Stop(HRESULT hr = S_OK) WI_NOEXCEPT \ - { \ - ActivityBase::Stop(hr); \ - } \ - void StartActivity() WI_NOEXCEPT \ - { \ - __WRITE_ACTIVITY_START(ActivityClassName); \ - } \ - void StartRelatedActivity() WI_NOEXCEPT \ - { \ - wil::details::SetRelatedActivityId(*this); \ - StartActivity(); \ - } \ - void StartActivityWithCorrelationVector(PCSTR correlationVector) WI_NOEXCEPT \ - { \ - __WRITE_ACTIVITY_START(ActivityClassName, TraceLoggingString(correlationVector, "__TlgCV__")); \ - } \ - WI_NODISCARD ActivityClassName Split() WI_NOEXCEPT \ - { \ - __FAIL_FAST_IMMEDIATE_ASSERT__(IsRunning()); \ - IncrementExpectedStopCount(); \ - return ActivityClassName(*this); \ - } \ - WI_NODISCARD ActivityClassName TransferToCurrentThread() WI_NOEXCEPT \ - { \ - return ActivityClassName(wistd::move(*this), IsRunning()); \ - } \ - WI_NODISCARD ActivityClassName TransferToMember() WI_NOEXCEPT \ - { \ - return ActivityClassName(wistd::move(*this), false); \ +#define __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, ...) \ + class ActivityClassName final : public wil::ActivityBase \ + { \ + protected: \ + void StopActivity() WI_NOEXCEPT override \ + { \ + __WRITE_ACTIVITY_STOP(ActivityClassName); \ + } \ + bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT override \ + { \ + return TraceLoggingType::WasAlreadyReportedToTelemetry(failureId); \ + } \ + \ + public: \ + static bool IsEnabled() WI_NOEXCEPT \ + { \ + return TraceLoggingType::IsEnabled(); \ + } \ + ~ActivityClassName() WI_NOEXCEPT \ + { \ + ActivityBase::Destroy(); \ + } \ + ActivityClassName(ActivityClassName const &other) WI_NOEXCEPT : ActivityBase(other) \ + { \ + } \ + ActivityClassName(ActivityClassName &&other) WI_NOEXCEPT : ActivityBase(wistd::move(other)) \ + { \ + } \ + ActivityClassName(ActivityClassName &&other, bool shouldWatchErrors) WI_NOEXCEPT \ + : ActivityBase(wistd::move(other), shouldWatchErrors) \ + { \ + } \ + ActivityClassName &operator=(ActivityClassName const &other) WI_NOEXCEPT \ + { \ + ActivityBase::operator=(other); \ + return *this; \ + } \ + ActivityClassName &operator=(ActivityClassName &&other) WI_NOEXCEPT \ + { \ + auto localActivity(wistd::move(*this)); \ + ActivityBase::operator=(wistd::move(other)); \ + return *this; \ + } \ + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT \ + { \ + return IsRunning(); \ + } \ + void StopWithResult(HRESULT hr) \ + { \ + ActivityBase::Stop(hr); \ + } \ + template void StopWithResult(HRESULT hr, TArgs &&...args) \ + { \ + SetStopResult(hr); \ + Stop(wistd::forward(args)...); \ + } \ + void Stop(HRESULT hr = S_OK) WI_NOEXCEPT \ + { \ + ActivityBase::Stop(hr); \ + } \ + void StartActivity() WI_NOEXCEPT \ + { \ + __WRITE_ACTIVITY_START(ActivityClassName); \ + } \ + void StartRelatedActivity() WI_NOEXCEPT \ + { \ + wil::details::SetRelatedActivityId(*this); \ + StartActivity(); \ + } \ + void StartActivityWithCorrelationVector(PCSTR correlationVector) WI_NOEXCEPT \ + { \ + __WRITE_ACTIVITY_START(ActivityClassName, TraceLoggingString(correlationVector, "__TlgCV__")); \ + } \ + WI_NODISCARD ActivityClassName Split() WI_NOEXCEPT \ + { \ + __FAIL_FAST_IMMEDIATE_ASSERT__(IsRunning()); \ + IncrementExpectedStopCount(); \ + return ActivityClassName(*this); \ + } \ + WI_NODISCARD ActivityClassName TransferToCurrentThread() WI_NOEXCEPT \ + { \ + return ActivityClassName(wistd::move(*this), IsRunning()); \ + } \ + WI_NODISCARD ActivityClassName TransferToMember() WI_NOEXCEPT \ + { \ + return ActivityClassName(wistd::move(*this), false); \ } -#define __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) \ -private: \ - template \ - ActivityClassName(wil::details::tag_start, TArgs&&... args) WI_NOEXCEPT : ActivityBase(#ActivityClassName) \ - { \ - StartActivity(wistd::forward(args)...); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); \ - } \ - template \ - ActivityClassName(wil::details::tag_start_cv, _In_opt_ PCSTR correlationVector, TArgs&&... args) WI_NOEXCEPT \ - : ActivityBase(#ActivityClassName) \ - { \ - StartActivityWithCorrelationVector(correlationVector, wistd::forward(args)...); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); \ - } \ -\ -public: \ - ActivityClassName() WI_NOEXCEPT : ActivityBase(#ActivityClassName, false) \ - { \ - } \ - template \ - WI_NODISCARD static ActivityClassName Start(TArgs&&... args) \ - { \ - return ActivityClassName(wil::details::tag_start(), wistd::forward(args)...); \ - } \ - template \ - WI_NODISCARD static ActivityClassName StartWithCorrelationVector(_In_ PCSTR correlationVector, TArgs&&... args) \ - { \ - return ActivityClassName(wil::details::tag_start_cv(), correlationVector, wistd::forward(args)...); \ +#define __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) \ + private: \ + template \ + ActivityClassName(wil::details::tag_start, TArgs &&...args) WI_NOEXCEPT : ActivityBase(#ActivityClassName) \ + { \ + StartActivity(wistd::forward(args)...); \ + __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); \ + } \ + template \ + ActivityClassName(wil::details::tag_start_cv, _In_opt_ PCSTR correlationVector, TArgs &&...args) WI_NOEXCEPT \ + : ActivityBase(#ActivityClassName) \ + { \ + StartActivityWithCorrelationVector(correlationVector, wistd::forward(args)...); \ + __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); \ + } \ + \ + public: \ + ActivityClassName() WI_NOEXCEPT : ActivityBase(#ActivityClassName, false) \ + { \ + } \ + template WI_NODISCARD static ActivityClassName Start(TArgs &&...args) \ + { \ + return ActivityClassName(wil::details::tag_start(), wistd::forward(args)...); \ + } \ + template \ + WI_NODISCARD static ActivityClassName StartWithCorrelationVector(_In_ PCSTR correlationVector, TArgs &&...args) \ + { \ + return ActivityClassName(wil::details::tag_start_cv(), correlationVector, wistd::forward(args)...); \ } -#define __IMPLEMENT_CALLCONTEXT_CLASS(ActivityClassName) \ -protected: \ - ActivityClassName(_In_opt_ void**, PCSTR contextName, _In_ _Printf_format_string_ PCSTR formatString, _In_opt_ va_list argList) : \ - ActivityBase(contextName) \ - { \ - GetCallContext()->SetMessage(formatString, argList); \ - StartActivity(); \ - } \ - ActivityClassName(_In_opt_ void**, PCSTR contextName) : ActivityBase(contextName) \ - { \ - StartActivity(); \ - } \ -\ -public: \ - ActivityClassName(PCSTR contextName) : ActivityBase(contextName, false) \ - { \ - } \ - ActivityClassName(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT : ActivityClassName(contextName) \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - GetCallContext()->SetMessage(formatString, argList); \ - } \ - WI_NODISCARD static ActivityClassName Start(PCSTR contextName) WI_NOEXCEPT \ - { \ - return ActivityClassName(static_cast(__nullptr), contextName); \ - } \ - WI_NODISCARD static ActivityClassName Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - return ActivityClassName(static_cast(__nullptr), contextName, formatString, argList); \ +#define __IMPLEMENT_CALLCONTEXT_CLASS(ActivityClassName) \ + protected: \ + ActivityClassName(_In_opt_ void **, PCSTR contextName, _In_ _Printf_format_string_ PCSTR formatString, \ + _In_opt_ va_list argList) \ + : ActivityBase(contextName) \ + { \ + GetCallContext()->SetMessage(formatString, argList); \ + StartActivity(); \ + } \ + ActivityClassName(_In_opt_ void **, PCSTR contextName) : ActivityBase(contextName) \ + { \ + StartActivity(); \ + } \ + \ + public: \ + ActivityClassName(PCSTR contextName) : ActivityBase(contextName, false) \ + { \ + } \ + ActivityClassName(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ + : ActivityClassName(contextName) \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + GetCallContext()->SetMessage(formatString, argList); \ + } \ + WI_NODISCARD static ActivityClassName Start(PCSTR contextName) WI_NOEXCEPT \ + { \ + return ActivityClassName(static_cast(__nullptr), contextName); \ + } \ + WI_NODISCARD static ActivityClassName Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) \ + WI_NOEXCEPT \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + return ActivityClassName(static_cast(__nullptr), contextName, formatString, argList); \ } -#define __END_TRACELOGGING_ACTIVITY_CLASS() \ - } \ +#define __END_TRACELOGGING_ACTIVITY_CLASS() \ + } \ ; /// @endcond #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ - void EventId() \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ + void EventId() \ + { \ + __WI_TraceLoggingWriteTagged(*this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ - void EventId() \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ + void EventId() \ + { \ + __WI_TraceLoggingWriteTagged(*this, #EventId, ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ - void EventId(PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ + void EventId(PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged(*this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ - void EventId(PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ + void EventId(PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingString(correlationVector, "__TlgCV__"), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template \ - void EventId(T1&& varName1) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ + template void EventId(T1 &&varName1) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template \ - void EventId(T1&& varName1) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, #EventId, TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ + template void EventId(T1 &&varName1) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template \ - void EventId(T1&& varName1, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ + template void EventId(T1 &&varName1, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template \ - void EventId(T1&& varName1, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ + template void EventId(T1 &&varName1, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template void EventId(T1 &&varName1, T2 &&varName2) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template void EventId(T1 &&varName1, T2 &&varName2) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + ...) \ + template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + ...) \ + template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7, VarType8, varName8, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7, VarType8, varName8, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9) \ - { \ - __WI_TraceLoggingWriteTagged( \ - *this, \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - ##__VA_ARGS__); \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9) \ + { \ + __WI_TraceLoggingWriteTagged( \ + *this, #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + ##__VA_ARGS__); \ } #endif -#define DEFINE_TAGGED_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) \ DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, UINT32, varName, ##__VA_ARGS__) -#define DEFINE_TAGGED_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) \ DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, bool, varName, ##__VA_ARGS__) -#define DEFINE_TAGGED_TRACELOGGING_EVENT_STRING(EventId, varName, ...) \ +#define DEFINE_TAGGED_TRACELOGGING_EVENT_STRING(EventId, varName, ...) \ DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, PCWSTR, varName, ##__VA_ARGS__) // Internal MACRO implementation of TraceLogging classes. // Do NOT use these macros directly. /// @cond -#define __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingProviderOwnerClassName) \ -public: \ - typedef TraceLoggingProviderOwnerClassName TraceLoggingType; \ - static bool IsEnabled( \ - UCHAR eventLevel = 0 /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, \ - ULONGLONG eventKeywords = 0 /* MICROSOFT_KEYWORD_XXX */) WI_NOEXCEPT \ - { \ - return Instance()->IsEnabled_(eventLevel, eventKeywords); \ - } \ - static TraceLoggingHProvider Provider() WI_NOEXCEPT \ - { \ - return static_cast(Instance())->Provider_(); \ - } \ - static void SetTelemetryEnabled(bool) WI_NOEXCEPT \ - { \ - } \ - static void SetErrorReportingType(wil::ErrorReportingType type) WI_NOEXCEPT \ - { \ - return Instance()->SetErrorReportingType_(type); \ - } \ - static void __stdcall FallbackTelemetryCallback(bool alreadyReported, wil::FailureInfo const& failure) WI_NOEXCEPT \ - { \ - return Instance()->OnErrorReported(alreadyReported, failure); \ - } \ - WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread(PCSTR contextName) WI_NOEXCEPT \ - { \ - return wil::ActivityThreadWatcher(Instance(), contextName); \ - } \ - WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread( \ - PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - return wil::ActivityThreadWatcher(Instance(), contextName, formatString, argList); \ - } \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(CallContext, wil::ActivityOptions::TelemetryOnFailure) \ - __IMPLEMENT_CALLCONTEXT_CLASS(CallContext); \ - __END_TRACELOGGING_ACTIVITY_CLASS(); \ - static CallContext Start(PCSTR contextName) WI_NOEXCEPT \ - { \ - return CallContext(contextName, __nullptr, __nullptr); \ - } \ - static CallContext Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - return CallContext(contextName, formatString, argList); \ - } \ - static void TraceLoggingInfo(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - return Instance()->ReportTraceLoggingMessage(formatString, argList); \ - } \ - static void TraceLoggingError(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { \ - va_list argList; \ - va_start(argList, formatString); \ - return Instance()->ReportTraceLoggingError(formatString, argList); \ - } \ -\ -private: \ - TraceLoggingHProvider Provider_() const WI_NOEXCEPT = delete; \ - TraceLoggingClassName() WI_NOEXCEPT{}; \ -\ -protected: \ - static TraceLoggingClassName* Instance() WI_NOEXCEPT \ - { \ - static wil::details::static_lazy wrapper; \ - return wrapper.get([]() { \ - wrapper.cleanup(); \ - }); \ - } \ +#define __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingProviderOwnerClassName) \ + public: \ + typedef TraceLoggingProviderOwnerClassName TraceLoggingType; \ + static bool IsEnabled(UCHAR eventLevel = 0 /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, \ + ULONGLONG eventKeywords = 0 /* MICROSOFT_KEYWORD_XXX */) WI_NOEXCEPT \ + { \ + return Instance()->IsEnabled_(eventLevel, eventKeywords); \ + } \ + static TraceLoggingHProvider Provider() WI_NOEXCEPT \ + { \ + return static_cast(Instance())->Provider_(); \ + } \ + static void SetTelemetryEnabled(bool) WI_NOEXCEPT \ + { \ + } \ + static void SetErrorReportingType(wil::ErrorReportingType type) WI_NOEXCEPT \ + { \ + return Instance()->SetErrorReportingType_(type); \ + } \ + static void __stdcall FallbackTelemetryCallback(bool alreadyReported, wil::FailureInfo const &failure) WI_NOEXCEPT \ + { \ + return Instance()->OnErrorReported(alreadyReported, failure); \ + } \ + WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread(PCSTR contextName) WI_NOEXCEPT \ + { \ + return wil::ActivityThreadWatcher(Instance(), contextName); \ + } \ + WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread( \ + PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + return wil::ActivityThreadWatcher(Instance(), contextName, formatString, argList); \ + } \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(CallContext, wil::ActivityOptions::TelemetryOnFailure) \ + __IMPLEMENT_CALLCONTEXT_CLASS(CallContext); \ + __END_TRACELOGGING_ACTIVITY_CLASS(); \ + static CallContext Start(PCSTR contextName) WI_NOEXCEPT \ + { \ + return CallContext(contextName, __nullptr, __nullptr); \ + } \ + static CallContext Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + return CallContext(contextName, formatString, argList); \ + } \ + static void TraceLoggingInfo(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + return Instance()->ReportTraceLoggingMessage(formatString, argList); \ + } \ + static void TraceLoggingError(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ + { \ + va_list argList; \ + va_start(argList, formatString); \ + return Instance()->ReportTraceLoggingError(formatString, argList); \ + } \ + \ + private: \ + TraceLoggingHProvider Provider_() const WI_NOEXCEPT = delete; \ + TraceLoggingClassName() WI_NOEXCEPT{}; \ + \ + protected: \ + static TraceLoggingClassName *Instance() WI_NOEXCEPT \ + { \ + static wil::details::static_lazy wrapper; \ + return wrapper.get([]() { wrapper.cleanup(); }); \ + } \ friend class wil::details::static_lazy; #define __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOption) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ -private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ + __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ + private: \ + struct StaticHandle \ + { \ + TraceLoggingHProvider handle; \ + StaticHandle() WI_NOEXCEPT \ + { \ + TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ -\ -protected: \ - void Create() WI_NOEXCEPT \ - { \ - Register(m_staticHandle.handle); \ - } \ -\ -public: + handle = &__hInner; \ + } \ + } m_staticHandle; \ + \ + protected: \ + void Create() WI_NOEXCEPT \ + { \ + Register(m_staticHandle.handle); \ + } \ + \ + public: -#define __IMPLEMENT_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ - __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) +#define __IMPLEMENT_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ + __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, \ + TraceLoggingOptionMicrosoftTelemetry()) -#define __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOption) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ -private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ +#define __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, \ + TraceLoggingOption) \ + __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ + private: \ + struct StaticHandle \ + { \ + TraceLoggingHProvider handle; \ + StaticHandle() WI_NOEXCEPT \ + { \ + TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ - static VOID NTAPI Callback( \ - _In_ const GUID* SourceId, \ - ULONG ControlCode, \ - UCHAR Level, \ - ULONGLONG MatchAnyKeyword, \ - ULONGLONG MatchAllKeyword, \ - _In_opt_ EVENT_FILTER_DESCRIPTOR* FilterData, \ - void* CallbackContext); \ -\ -protected: \ - void Create() WI_NOEXCEPT \ - { \ - Register(m_staticHandle.handle, &TraceLoggingClassName::Callback); \ - } \ -\ -public: + handle = &__hInner; \ + } \ + } m_staticHandle; \ + static VOID NTAPI Callback(_In_ const GUID *SourceId, ULONG ControlCode, UCHAR Level, ULONGLONG MatchAnyKeyword, \ + ULONGLONG MatchAllKeyword, _In_opt_ EVENT_FILTER_DESCRIPTOR *FilterData, \ + void *CallbackContext); \ + \ + protected: \ + void Create() WI_NOEXCEPT \ + { \ + Register(m_staticHandle.handle, &TraceLoggingClassName::Callback); \ + } \ + \ + public: -#define __IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ -private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId); \ +#define __IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ + __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ + private: \ + struct StaticHandle \ + { \ + TraceLoggingHProvider handle; \ + StaticHandle() WI_NOEXCEPT \ + { \ + TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId); \ _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ -\ -protected: \ - void Create() WI_NOEXCEPT \ - { \ - Register(m_staticHandle.handle); \ - } \ -\ -public: + handle = &__hInner; \ + } \ + } m_staticHandle; \ + \ + protected: \ + void Create() WI_NOEXCEPT \ + { \ + Register(m_staticHandle.handle); \ + } \ + \ + public: /// @endcond #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ - static void EventId() \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ + static void EventId() \ + { \ + TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ - static void EventId() \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ + static void EventId() \ + { \ + TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ - static void EventId(PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), #EventId, _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ + static void EventId(PCSTR correlationVector) \ + { \ + TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, _GENERIC_PARTB_FIELDS_ENABLED, \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ - static void EventId(PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ + static void EventId(PCSTR correlationVector) \ + { \ + TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, TraceLoggingString(correlationVector, "__TlgCV__"), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template \ - static void EventId(T1&& varName1) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ + template static void EventId(T1 &&varName1) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template \ - static void EventId(T1&& varName1) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ + template static void EventId(T1 &&varName1) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template \ - static void EventId(T1&& varName1, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ + template static void EventId(T1 &&varName1, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template \ - static void EventId(T1&& varName1, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ + template static void EventId(T1 &&varName1, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ + template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, \ + PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, \ + PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - static void EventId(T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM9_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM9_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9, PCSTR correlationVector) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9, PCSTR correlationVector) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + TraceLoggingString(correlationVector, "__TlgCV__"), ##__VA_ARGS__); \ } #endif #ifdef _GENERIC_PARTB_FIELDS_ENABLED -#define DEFINE_TRACELOGGING_EVENT_PARAM10( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - VarType10, \ - varName10, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9, T10&& varName10) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM10(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9, T10 &&varName10) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ + _GENERIC_PARTB_FIELDS_ENABLED, ##__VA_ARGS__); \ } #else -#define DEFINE_TRACELOGGING_EVENT_PARAM10( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - VarType10, \ - varName10, \ - ...) \ - template \ - static void EventId( \ - T1&& varName1, T2&& varName2, T3&& varName3, T4&& varName4, T5&& varName5, T6&& varName6, T7&& varName7, T8&& varName8, T9&& varName9, T10&& varName10) \ - { \ - TraceLoggingWrite( \ - TraceLoggingType::Provider(), \ - #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ - ##__VA_ARGS__); \ +#define DEFINE_TRACELOGGING_EVENT_PARAM10(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, ...) \ + template \ + static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, \ + T7 &&varName7, T8 &&varName8, T9 &&varName9, T10 &&varName10) \ + { \ + TraceLoggingWrite( \ + TraceLoggingType::Provider(), #EventId, \ + TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ + TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ + TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ + TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ + TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ + TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ + TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ + TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ + TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ + TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ + ##__VA_ARGS__); \ } #endif -#define DEFINE_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) \ +#define DEFINE_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, UINT32, varName, ##__VA_ARGS__) -#define DEFINE_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) \ +#define DEFINE_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, bool, varName, ##__VA_ARGS__) -#define DEFINE_TRACELOGGING_EVENT_STRING(EventId, varName, ...) \ +#define DEFINE_TRACELOGGING_EVENT_STRING(EventId, varName, ...) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, PCWSTR, varName, ##__VA_ARGS__) // Declaring a pure TraceLogging class // To declare a tracelogging class, declare your class derived from wil::TraceLoggingProvider, populate the uuid -// attribute of the class with the GUID of your provider, and then include the IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY -// macro within your class. +// attribute of the class with the GUID of your provider, and then include the +// IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY macro within your class. // -// If you want to register a provider using a callback to log events, you can instead use the IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK -// Additionally your tracelogging class will have to implement a static Callback method. See the declaration within __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB. +// If you want to register a provider using a callback to log events, you can instead use the +// IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK Additionally your tracelogging class will have to +// implement a static Callback method. See the declaration within __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB. // // If you don't need or use telemetry, you can instead use the IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY. // This prevents telemetry from enabling your provider even if you're not using telemetry. -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ +#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, GroupName) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ +#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, GroupName) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_WINDOWS_CORE_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionWindowsCoreTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ +#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ + IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, \ + TraceLoggingOptionMicrosoftTelemetry()) +#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK(TraceLoggingClassName, ProviderName, \ + ProviderId) \ + IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, \ + TraceLoggingOptionMicrosoftTelemetry()) +#define IMPLEMENT_TRACELOGGING_CLASS_WITH_WINDOWS_CORE_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ + IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, \ + TraceLoggingOptionWindowsCoreTelemetry()) +#define IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ __IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) #ifndef WIL_HIDE_DEPRECATED_1612 @@ -3248,46 +2969,48 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") // This is recommended only for simple TraceLogging events. Telemetry events and activities are better defined // within your Tracelogging class using one of the macros below. -#define TraceLoggingProviderWrite(TraceLoggingClassName, EventId, ...) \ +#define TraceLoggingProviderWrite(TraceLoggingClassName, EventId, ...) \ TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, ##__VA_ARGS__) -#define TraceLoggingProviderWriteTelemetry(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite( \ - TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), ##__VA_ARGS__) +#define TraceLoggingProviderWriteTelemetry(TraceLoggingClassName, EventId, ...) \ + TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), ##__VA_ARGS__) -#define TraceLoggingProviderWriteMeasure(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite( \ - TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), ##__VA_ARGS__) +#define TraceLoggingProviderWriteMeasure(TraceLoggingClassName, EventId, ...) \ + TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), ##__VA_ARGS__) -#define TraceLoggingProviderWriteCriticalData(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite( \ - TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), ##__VA_ARGS__) +#define TraceLoggingProviderWriteCriticalData(TraceLoggingClassName, EventId, ...) \ + TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), ##__VA_ARGS__) // [Optional] Custom Events -// Use these macros to define a Custom Event for a Provider. Use the TraceLoggingClassWrite or TraceLoggingClassWriteTelemetry -// from within a custom event to issue the event. Methods will be a no-op (and not be called) if the provider is not -// enabled. +// Use these macros to define a Custom Event for a Provider. Use the TraceLoggingClassWrite or +// TraceLoggingClassWriteTelemetry from within a custom event to issue the event. Methods will be a no-op (and not be +// called) if the provider is not enabled. #define TraceLoggingClassWrite(EventId, ...) TraceLoggingWrite(TraceLoggingType::Provider(), EventId, ##__VA_ARGS__) -#define TraceLoggingClassWriteTelemetry(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), ##__VA_ARGS__) +#define TraceLoggingClassWriteTelemetry(EventId, ...) \ + TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + ##__VA_ARGS__) -#define TraceLoggingClassWriteMeasure(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), ##__VA_ARGS__) +#define TraceLoggingClassWriteMeasure(EventId, ...) \ + TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + ##__VA_ARGS__) -#define TraceLoggingClassWriteCriticalData(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), ##__VA_ARGS__) +#define TraceLoggingClassWriteCriticalData(EventId, ...) \ + TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + ##__VA_ARGS__) -#define DEFINE_EVENT_METHOD(MethodName) \ - template \ - static void MethodName(TArgs&&... args) WI_NOEXCEPT \ - { \ - if (IsEnabled()) \ - { \ - Instance()->MethodName##_(wistd::forward(args)...); \ - } \ - } \ +#define DEFINE_EVENT_METHOD(MethodName) \ + template static void MethodName(TArgs &&...args) WI_NOEXCEPT \ + { \ + if (IsEnabled()) \ + { \ + Instance()->MethodName##_(wistd::forward(args)...); \ + } \ + } \ void MethodName##_ // [Optional] Simple Events @@ -3304,126 +3027,78 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_TELEMETRY_EVENT(EventId) DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT(EventId) \ + DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ +#define DEFINE_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_CV(EventId) DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ +#define DEFINE_TELEMETRY_EVENT_CV(EventId) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TELEMETRY_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) #define DEFINE_TELEMETRY_EVENT_UINT32(EventId, varName) DEFINE_TELEMETRY_EVENT_PARAM1(EventId, UINT32, varName) #define DEFINE_TELEMETRY_EVENT_BOOL(EventId, varName) DEFINE_TELEMETRY_EVENT_PARAM1(EventId, bool, varName) @@ -3431,398 +3106,153 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #endif -#define DEFINE_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_CV(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV( \ - EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, \ - VarType1, \ - varName1, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM3_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - EventTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_CV(EventId, PrivacyTag, EventTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM4_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM7_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM8_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // [Optional] Simple Events @@ -3830,125 +3260,75 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_MEASURES_EVENT(EventId) DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ +#define DEFINE_MEASURES_EVENT(EventId) \ + DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_CV(EventId) DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ +#define DEFINE_MEASURES_EVENT_CV(EventId) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_MEASURES_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) #define DEFINE_MEASURES_EVENT_UINT32(EventId, varName) DEFINE_MEASURES_EVENT_PARAM1(EventId, UINT32, varName) #define DEFINE_MEASURES_EVENT_BOOL(EventId, varName) DEFINE_MEASURES_EVENT_PARAM1(EventId, bool, varName) @@ -3956,527 +3336,173 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #endif -#define DEFINE_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM9( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM10( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - VarType10, \ - varName10) \ - DEFINE_TRACELOGGING_EVENT_PARAM10( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - VarType10, \ - varName10, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM9(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + VarType7, varName7, VarType8, varName8, VarType9, varName9) \ + DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, VarType9, varName9, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM10( \ + EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, \ + varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10) \ + DEFINE_TRACELOGGING_EVENT_PARAM10( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_CV(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV( \ - EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM3_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - EventTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM9_CV( \ - EventId, \ - PrivacyTag, \ - EventTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_CV(EventId, PrivacyTag, EventTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM4_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM7_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM8_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM9_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ + DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, VarType9, varName9, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // [Optional] Simple Events @@ -4484,128 +3510,80 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_CRITICAL_DATA_EVENT(EventId) \ +#define DEFINE_CRITICAL_DATA_EVENT(EventId) \ DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ +#define DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_CV(EventId) \ +#define DEFINE_CRITICAL_DATA_EVENT_CV(EventId) \ DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) #define DEFINE_CRITICAL_DATA_EVENT_UINT32(EventId, varName) DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, UINT32, varName) #define DEFINE_CRITICAL_DATA_EVENT_BOOL(EventId, varName) DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, bool, varName) @@ -4613,442 +3591,164 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #endif -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, \ + varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV( \ - EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV( \ - EventId, \ - VarType1, \ - varName1, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM3_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM4_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM5_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM6_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM7_CV( \ - EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM8_CV( \ - EventId, \ - PrivacyTag, \ - EventTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM9_CV( \ - EventId, \ - PrivacyTag, \ - EventTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag), \ - TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag, EventTag) \ + DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ + DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2) \ + DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3) \ + DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM4_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ + DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5) \ + DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, \ + VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM7_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM8_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) +#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM9_CV( \ + EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, \ + VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ + DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, \ + varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, \ + VarType8, varName8, VarType9, varName9, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // Custom Activities @@ -5056,94 +3756,103 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") // you can use the (TODO: LIST MACRO NAMES) macros to add behavior. // [optional] params are: Options, Keyword, Level, PrivacyTag -#define BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, ...) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, ##__VA_ARGS__) \ +#define BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, ...) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, ##__VA_ARGS__) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // [optional] param is: Level, PrivacyTag #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ +#define BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level) \ +#define BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) #endif -#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ +#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, WINEVENT_LEVEL_VERBOSE, \ + PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level, PrivacyTag) \ +#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // [optional] param is: Level #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure) \ +#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level) \ +#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) #endif -#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ +#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, \ + WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level, PrivacyTag) \ +#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level, \ + PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // [optional] param is: Level #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY) \ +#define BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_TELEMETRY) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, Level) \ +#define BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_TELEMETRY, Level) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) #endif -#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ +#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_TELEMETRY, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, Level, PrivacyTag) \ +#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_TELEMETRY, Level, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // [optional] param is: Level #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES) \ +#define BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_MEASURES) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, Level) \ +#define BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_MEASURES, Level) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) #endif -#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ +#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_MEASURES, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, Level, PrivacyTag) \ +#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_MEASURES, Level, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // [optional] param is: Level #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA) \ +#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_CRITICAL_DATA) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, Level) \ +#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_CRITICAL_DATA, Level) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) #endif -#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ +#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_CRITICAL_DATA, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS( \ - ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, Level, PrivacyTag) \ +#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, \ + MICROSOFT_KEYWORD_CRITICAL_DATA, Level, PrivacyTag) \ __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) // Use to end ALL activity class definitions @@ -5155,69 +3864,69 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") // [optional] params are: Options, Keyword, Level #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_CUSTOM_ACTIVITY(ActivityClassName, ...) \ - BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, ##__VA_ARGS__) \ +#define DEFINE_CUSTOM_ACTIVITY(ActivityClassName, ...) \ + BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, ##__VA_ARGS__) \ END_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_ACTIVITY(ActivityClassName) \ - BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_TRACELOGGING_ACTIVITY(ActivityClassName) \ + BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ END_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ +#define DEFINE_TRACELOGGING_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ + BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ END_ACTIVITY_CLASS() -#define DEFINE_CALLCONTEXT_ACTIVITY(ActivityClassName) \ - BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_CALLCONTEXT_ACTIVITY(ActivityClassName) \ + BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) \ END_ACTIVITY_CLASS() -#define DEFINE_CALLCONTEXT_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ +#define DEFINE_CALLCONTEXT_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ + BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ END_ACTIVITY_CLASS() -#define DEFINE_TELEMETRY_ACTIVITY(ActivityClassName) \ - BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_TELEMETRY_ACTIVITY(ActivityClassName) \ + BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) \ END_ACTIVITY_CLASS() -#define DEFINE_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ +#define DEFINE_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ + BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ END_ACTIVITY_CLASS() #endif -#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ +#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY(ActivityClassName, PrivacyTag) \ + BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ +#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ END_ACTIVITY_CLASS() #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_MEASURES_ACTIVITY(ActivityClassName) \ - BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_MEASURES_ACTIVITY(ActivityClassName) \ + BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) \ END_ACTIVITY_CLASS() -#define DEFINE_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ +#define DEFINE_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ + BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ END_ACTIVITY_CLASS() #endif -#define DEFINE_COMPLIANT_MEASURES_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ +#define DEFINE_COMPLIANT_MEASURES_ACTIVITY(ActivityClassName, PrivacyTag) \ + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ +#define DEFINE_COMPLIANT_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ END_ACTIVITY_CLASS() #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_CRITICAL_DATA_ACTIVITY(ActivityClassName) \ - BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_CRITICAL_DATA_ACTIVITY(ActivityClassName) \ + BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) \ END_ACTIVITY_CLASS() -#define DEFINE_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ +#define DEFINE_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ + BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ END_ACTIVITY_CLASS() #endif -#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ +#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY(ActivityClassName, PrivacyTag) \ + BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ +#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ + BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ END_ACTIVITY_CLASS() // [Optional] Custom Start or Stop Events for Activities @@ -5237,13 +3946,13 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #define TraceLoggingClassWriteTagged(EventId, ...) __WI_TraceLoggingWriteTagged(*this, #EventId, ##__VA_ARGS__) -#define TraceLoggingClassWriteTaggedTelemetry(EventId, ...) \ +#define TraceLoggingClassWriteTaggedTelemetry(EventId, ...) \ __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), ##__VA_ARGS__) -#define TraceLoggingClassWriteTaggedMeasure(EventId, ...) \ +#define TraceLoggingClassWriteTaggedMeasure(EventId, ...) \ __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), ##__VA_ARGS__) -#define TraceLoggingClassWriteTaggedCriticalData(EventId, ...) \ +#define TraceLoggingClassWriteTaggedCriticalData(EventId, ...) \ __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), ##__VA_ARGS__) // [Optional] Simple Tagged Events for Activities @@ -5251,260 +3960,143 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_TAGGED_TELEMETRY_EVENT(EventId) \ +#define DEFINE_TAGGED_TELEMETRY_EVENT(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_CV(EventId) \ +#define DEFINE_TAGGED_TELEMETRY_EVENT_CV(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) +#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_UINT32(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TAGGED_TELEMETRY_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_TELEMETRY_EVENT_STRING(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, PCWSTR, varName) +#define DEFINE_TAGGED_TELEMETRY_EVENT_UINT32(EventId, varName) \ + DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, UINT32, varName) +#define DEFINE_TAGGED_TELEMETRY_EVENT_BOOL(EventId, varName) \ + DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, bool, varName) +#define DEFINE_TAGGED_TELEMETRY_EVENT_STRING(EventId, varName) \ + DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, PCWSTR, varName) #endif -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ + DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // [Optional] Simple Tagged Events for Activities @@ -5512,259 +4104,142 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_TAGGED_MEASURES_EVENT(EventId) \ +#define DEFINE_TAGGED_MEASURES_EVENT(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_CV(EventId) \ +#define DEFINE_TAGGED_MEASURES_EVENT_CV(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) +#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_UINT32(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, UINT32, varName) +#define DEFINE_TAGGED_MEASURES_EVENT_UINT32(EventId, varName) \ + DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, UINT32, varName) #define DEFINE_TAGGED_MEASURES_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_MEASURES_EVENT_STRING(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, PCWSTR, varName) +#define DEFINE_TAGGED_MEASURES_EVENT_STRING(EventId, varName) \ + DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, PCWSTR, varName) #endif -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ + DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, \ + VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), \ TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // [Optional] Simple Tagged Events for Activities @@ -5772,427 +4247,279 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") #ifndef DISABLE_NONCOMPLIANT_TELEMETRY -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT(EventId) \ +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - VarType9, \ - varName9, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, VarType9, varName9, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_CV(EventId) \ +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_CV(EventId) \ DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8_CV( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, \ + varName3, VarType4, varName4, VarType5, varName5, VarType6, \ + varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, VarType8, varName8, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_UINT32(EventId, varName) \ +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_UINT32(EventId, varName) \ DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_STRING(EventId, varName) \ +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_BOOL(EventId, varName) \ + DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, bool, varName) +#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_STRING(EventId, varName) \ DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, PCWSTR, varName) #endif -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1( \ - EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2( \ - EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3( \ - EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7( \ - EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8( \ - EventId, \ - PrivacyTag, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ - EventId, \ - VarType1, \ - varName1, \ - VarType2, \ - varName2, \ - VarType3, \ - varName3, \ - VarType4, \ - varName4, \ - VarType5, \ - varName5, \ - VarType6, \ - varName6, \ - VarType7, \ - varName7, \ - VarType8, \ - varName8, \ - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ - TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ + DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2, VarType3, varName3) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2, VarType3, varName3, VarType4, varName4) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2, VarType3, varName3, VarType4, varName4, VarType5, \ + varName5) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2, VarType3, varName3, VarType4, varName4, VarType5, \ + varName5, VarType6, varName6) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, \ + varName2, VarType3, varName3, VarType4, varName4, VarType5, \ + varName5, VarType6, varName6, VarType7, varName7) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, \ + VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, \ + varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \ + TelemetryPrivacyDataTag(PrivacyTag)) +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8( \ + EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, \ + varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ + DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8( \ + EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, \ + VarType6, varName6, VarType7, varName7, VarType8, varName8, \ + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) \ +#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) \ DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) // Thread Activities [deprecated] -// These are desktop only and are not recommended by the fundamentals team. These activities lag behind regular activities in -// their ability to use CallContext or to be cross-thread portable, so their usage should be limited. +// These are desktop only and are not recommended by the fundamentals team. These activities lag behind regular +// activities in their ability to use CallContext or to be cross-thread portable, so their usage should be limited. #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ - class ActivityClassName final : public _TlgActivityBase \ - { \ - static const UINT64 PrivacyTag = 0; \ - friend class _TlgActivityBase; \ - void OnStarted() \ - { \ - PushThreadActivityId(); \ - } \ - void OnStopped() \ - { \ - PopThreadActivityId(); \ - } \ -\ - public: \ - ActivityClassName() : m_result(S_OK) \ - { \ - } \ -\ - private: \ - template \ - ActivityClassName(_In_ void**, TArgs&&... args) : m_result(S_OK) \ - { \ - StartActivity(wistd::forward(args)...); \ - } \ -\ - protected: \ - void EnsureWatchingCurrentThread() \ - { \ - } \ - void IgnoreCurrentThread() \ - { \ - } \ - wil::FailureInfo const* GetFailureInfo() \ - { \ - return (FAILED(m_result) && (m_cache.GetFailure() != nullptr) && (m_result == m_cache.GetFailure()->hr)) \ - ? m_cache.GetFailure() \ - : nullptr; \ - } \ - HRESULT GetResult() \ - { \ - return m_result; \ - } \ -\ - public: \ - ~ActivityClassName() \ - { \ - Stop(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); \ - } \ - ActivityClassName(ActivityClassName&&) = default; \ - WI_NODISCARD TraceLoggingHProvider Provider() const \ - { \ - return TraceLoggingType::Provider(); \ - } \ - void Stop(HRESULT hr = S_OK) \ - { \ - if (IsStarted()) \ - { \ - m_result = hr; \ - TRACELOGGING_WRITE_ACTIVITY_STOP(ActivityClassName); \ - } \ - } \ - template \ - void StopWithResult(HRESULT hr, TArgs&&... args) \ - { \ - m_result = hr; \ - Stop(wistd::forward(args)...); \ - } \ - template \ - static ActivityClassName Start(TArgs&&... args) \ - { \ - return ActivityClassName(static_cast(__nullptr), wistd::forward(args)...); \ - } \ - void StartActivity() \ - { \ - TRACELOGGING_WRITE_ACTIVITY_START(ActivityClassName); \ +#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ + class ActivityClassName final : public _TlgActivityBase \ + { \ + static const UINT64 PrivacyTag = 0; \ + friend class _TlgActivityBase; \ + void OnStarted() \ + { \ + PushThreadActivityId(); \ + } \ + void OnStopped() \ + { \ + PopThreadActivityId(); \ + } \ + \ + public: \ + ActivityClassName() : m_result(S_OK) \ + { \ + } \ + \ + private: \ + template ActivityClassName(_In_ void **, TArgs &&...args) : m_result(S_OK) \ + { \ + StartActivity(wistd::forward(args)...); \ + } \ + \ + protected: \ + void EnsureWatchingCurrentThread() \ + { \ + } \ + void IgnoreCurrentThread() \ + { \ + } \ + wil::FailureInfo const *GetFailureInfo() \ + { \ + return (FAILED(m_result) && (m_cache.GetFailure() != nullptr) && (m_result == m_cache.GetFailure()->hr)) \ + ? m_cache.GetFailure() \ + : nullptr; \ + } \ + HRESULT GetResult() \ + { \ + return m_result; \ + } \ + \ + public: \ + ~ActivityClassName() \ + { \ + Stop(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); \ + } \ + ActivityClassName(ActivityClassName &&) = default; \ + WI_NODISCARD TraceLoggingHProvider Provider() const \ + { \ + return TraceLoggingType::Provider(); \ + } \ + void Stop(HRESULT hr = S_OK) \ + { \ + if (IsStarted()) \ + { \ + m_result = hr; \ + TRACELOGGING_WRITE_ACTIVITY_STOP(ActivityClassName); \ + } \ + } \ + template void StopWithResult(HRESULT hr, TArgs &&...args) \ + { \ + m_result = hr; \ + Stop(wistd::forward(args)...); \ + } \ + template static ActivityClassName Start(TArgs &&...args) \ + { \ + return ActivityClassName(static_cast(__nullptr), wistd::forward(args)...); \ + } \ + void StartActivity() \ + { \ + TRACELOGGING_WRITE_ACTIVITY_START(ActivityClassName); \ } -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, WINEVENT_LEVEL_VERBOSE) +#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ + BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, \ + WINEVENT_LEVEL_VERBOSE) -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ +#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, 0, level) -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ +#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, 0, WINEVENT_LEVEL_VERBOSE) -#define END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() \ -private: \ - HRESULT m_result; \ - wil::ThreadFailureCache m_cache; \ - } \ +#define END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() \ + private: \ + HRESULT m_result; \ + wil::ThreadFailureCache m_cache; \ + } \ ; -#define BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ +#define BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, MICROSOFT_KEYWORD_TELEMETRY) #define END_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS() END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ +#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ + BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD(ActivityClassName, keyword) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ +#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD(ActivityClassName, keyword) \ + BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_LEVEL(ActivityClassName, level) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ +#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_LEVEL(ActivityClassName, level) \ + BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY(ActivityClassName) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_TRACELOGGING_THREAD_ACTIVITY(ActivityClassName) \ + BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() -#define DEFINE_TELEMETRY_THREAD_ACTIVITY(ActivityClassName) \ - BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ +#define DEFINE_TELEMETRY_THREAD_ACTIVITY(ActivityClassName) \ + BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ END_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS() #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ @@ -6247,410 +4574,421 @@ private: \ #define __DEFINE_TAGGED_EVENT_STRING DEFINE_TAGGED_TRACELOGGING_EVENT_STRING /// @endcond -template -class ActivityErrorTracer +template class ActivityErrorTracer { -public: - ActivityErrorTracer(T const&) + public: + ActivityErrorTracer(T const &) { } }; using TelemetryBase = wil::TraceLoggingProvider; -#define TRACELOGGING_WRITE_EVENT(TraceLoggingClassName, EventId, ...) \ +#define TRACELOGGING_WRITE_EVENT(TraceLoggingClassName, EventId, ...) \ TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, ##__VA_ARGS__) -#define TELEMETRY_WRITE_EVENT(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), ##__VA_ARGS__) +#define TELEMETRY_WRITE_EVENT(EventId, ...) \ + TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), \ + ##__VA_ARGS__) -#define DEFINE_TAGGED_EVENT_METHOD(MethodName) \ -public: \ +#define DEFINE_TAGGED_EVENT_METHOD(MethodName) \ + public: \ void MethodName #define DEFINE_ACTIVITY_START(...) void StartActivity(__VA_ARGS__) #define DEFINE_ACTIVITY_STOP(...) void Stop(__VA_ARGS__) -#define DECLARE_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ - class TraceLoggingClassName : public wil::TraceLoggingProvider \ - { \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId); \ +#define DECLARE_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ + class TraceLoggingClassName : public wil::TraceLoggingProvider \ + { \ + IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId); \ }; -#define IMPLEMENT_TELEMETRY_CLASS(TelemetryClassName, TraceLoggingClassName) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TelemetryClassName, TraceLoggingClassName) \ -protected: \ - void Create() \ - { \ - AttachProvider(TraceLoggingClassName::Provider()); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(TelemetryClassName, TraceLoggingClassName); \ - } \ -\ -public: +#define IMPLEMENT_TELEMETRY_CLASS(TelemetryClassName, TraceLoggingClassName) \ + __IMPLEMENT_TRACELOGGING_CLASS_BASE(TelemetryClassName, TraceLoggingClassName) \ + protected: \ + void Create() \ + { \ + AttachProvider(TraceLoggingClassName::Provider()); \ + __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(TelemetryClassName, TraceLoggingClassName); \ + } \ + \ + public: namespace wil { -/// @cond -namespace details -{ + /// @cond + namespace details + { #ifdef WIL_API_TELEMETRY_SUSPEND_HANDLER #pragma detect_mismatch("ODR_violation_WIL_API_TELEMETRY_SUSPEND_HANDLER_mismatch", "1") #else #pragma detect_mismatch("ODR_violation_WIL_API_TELEMETRY_SUSPEND_HANDLER_mismatch", "0") #endif - class ApiTelemetryLogger : public wil::TraceLoggingProvider - { - // {fb7fcbc6-7156-5a5b-eabd-0be47b14f453} - IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY( - ApiTelemetryLogger, - "Microsoft.Windows.ApiTelemetry", - (0xfb7fcbc6, 0x7156, 0x5a5b, 0xea, 0xbd, 0x0b, 0xe4, 0x7b, 0x14, 0xf4, 0x53)); - - public: - // Used to store of list of APIs (with namespace, class, custom and call count data per API). - // This is public so that it can be unit tested. - class ApiDataList + class ApiTelemetryLogger : public wil::TraceLoggingProvider { - public: - struct ApiData - { - PCWSTR className = nullptr; - PCWSTR apiName = nullptr; - PCSTR specialization = nullptr; - volatile long* counterReference = nullptr; - wistd::unique_ptr next; + // {fb7fcbc6-7156-5a5b-eabd-0be47b14f453} + IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(ApiTelemetryLogger, "Microsoft.Windows.ApiTelemetry", + (0xfb7fcbc6, 0x7156, 0x5a5b, 0xea, 0xbd, 0x0b, 0xe4, + 0x7b, 0x14, 0xf4, 0x53)); - ApiData(PCWSTR className_, PCWSTR apiName_, PCSTR specialization_, volatile long* counterReference_) : - className(className_), apiName(apiName_), specialization(specialization_), counterReference(counterReference_) + public: + // Used to store of list of APIs (with namespace, class, custom and call count data per API). + // This is public so that it can be unit tested. + class ApiDataList + { + public: + struct ApiData { + PCWSTR className = nullptr; + PCWSTR apiName = nullptr; + PCSTR specialization = nullptr; + volatile long *counterReference = nullptr; + wistd::unique_ptr next; + + ApiData(PCWSTR className_, PCWSTR apiName_, PCSTR specialization_, volatile long *counterReference_) + : className(className_), apiName(apiName_), specialization(specialization_), + counterReference(counterReference_) + { + } + }; + + // Inserts a new Api call counter into the list, keeping the list sorted by className + void Insert(PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, + volatile long *counterReference) + { + wistd::unique_ptr newApiData( + new (std::nothrow) ApiData(className, apiName, specialization, counterReference)); + if (newApiData) + { + auto lock = m_lock.lock_exclusive(); + + // Insert the new ApiData, keeping the list sorted by className. + wistd::unique_ptr *currentNode = &m_root; + while (*currentNode) + { + wistd::unique_ptr &node = *currentNode; + if (wcscmp(className, node->className) <= 0) + { + break; + } + currentNode = &(node->next); + } + newApiData->next.reset(currentNode->release()); + currentNode->reset(newApiData.release()); + } } - }; - // Inserts a new Api call counter into the list, keeping the list sorted by className - void Insert(PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, volatile long* counterReference) - { - wistd::unique_ptr newApiData(new (std::nothrow) ApiData(className, apiName, specialization, counterReference)); - if (newApiData) + // For each distinct namespace, calls the provided flushCallback function. + // After returning, it will have deleted all ApiData elements, and zeroed the *counterReference stored + // in each ApiData. + void Flush(wistd::function flushCallback) { - auto lock = m_lock.lock_exclusive(); + wistd::unique_ptr root; + if (m_root) + { + auto lock = m_lock.lock_exclusive(); + root.swap(m_root); + } - // Insert the new ApiData, keeping the list sorted by className. - wistd::unique_ptr* currentNode = &m_root; + while (root) + { + // First find the number of characters we need to allocate for each string, and the number of + // items in the counter array to allocate + size_t totalApiListLength = 1; // Init to 1 to account for null terminator + size_t totalSpecializationsLength = 1; // Init to 1 to account for null terminator + UINT16 numCounts = 0; + + ProcessSingleNamespace(&root, [&](wistd::unique_ptr &node) { + // Get the length needed for the class string + const wchar_t *strAfterNamespace = GetClassStringPointer(node->className); + size_t classStrLen = wcslen(strAfterNamespace ? strAfterNamespace : node->className); + + totalApiListLength += (classStrLen + wcslen(node->apiName) + + 1); // We add 1 to account for the comma delimiter + if (node->specialization) + { + totalSpecializationsLength += + strlen(node->specialization) + 1; // We add 1 to account for the comma delimiter + } + else + { + totalSpecializationsLength += 2; // '-' plus comma delimiter + } + numCounts++; + }); + + // Fill arrays with the API data, and then pass it to the callback function + wistd::unique_ptr apiList(new (std::nothrow) wchar_t[totalApiListLength]); + wistd::unique_ptr specializationList( + new (std::nothrow) char[totalSpecializationsLength]); + wistd::unique_ptr countArray(new (std::nothrow) UINT32[numCounts]); + size_t nameSpaceLength = GetNameSpaceLength(root->className) + 1; + wistd::unique_ptr nameSpace(new (std::nothrow) wchar_t[nameSpaceLength]); + if (!apiList || !specializationList || !countArray || !nameSpace) + { + return; + } + + ZeroMemory(apiList.get(), totalApiListLength * sizeof(wchar_t)); + ZeroMemory(specializationList.get(), totalSpecializationsLength * sizeof(char)); + ZeroMemory(countArray.get(), numCounts * sizeof(UINT32)); + ZeroMemory(nameSpace.get(), nameSpaceLength * sizeof(wchar_t)); + + StringCchCopyNW(nameSpace.get(), STRSAFE_MAX_CCH, root->className, nameSpaceLength - 1); + + int countArrayIndex = 0; + + wistd::unique_ptr *lastNamespaceNode = + ProcessSingleNamespace(&root, [&](wistd::unique_ptr &node) { + countArray[countArrayIndex] = + static_cast(::InterlockedExchangeNoFence(node->counterReference, 0)); + + // Prepend the portion of the apiName group string that's after the '.'. So for example, + // if the className is "Windows.System.Launcher", then we prepend "Launcher." to the + // apiName string. + const wchar_t *strAfterNamespace = GetClassStringPointer(node->className); + if (strAfterNamespace) + { + FAIL_FAST_IF_FAILED( + StringCchCatW(apiList.get(), totalApiListLength, strAfterNamespace + 1)); + FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L".")); + } + + FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, node->apiName)); + if (node->specialization) + { + FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, + node->specialization, strlen(node->specialization)) != 0); + } + else + { + FAIL_FAST_IF( + strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0); + } + + if (countArrayIndex != (numCounts - 1)) + { + FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L",")); + FAIL_FAST_IF( + strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0); + } + + countArrayIndex++; + }); + + // Call the callback function with the data we've collected for this namespace + flushCallback(nameSpace.get(), apiList.get(), specializationList.get(), countArray.get(), + numCounts); + + if (*lastNamespaceNode) + { + // Delete everything from the current root to the lastNamespaceNode + // (inclusive), considering the possibility that they are the same. Continue + // processing from the node following lastNamespaceNode, if any. root will + // be made to point to that. + auto newRoot = wistd::move((*lastNamespaceNode)->next); + const auto toDelete = wistd::move(root); + root = wistd::move(newRoot); + } + else + { + root.reset(); + } + } + } + + private: + static wistd::unique_ptr *ProcessSingleNamespace( + wistd::unique_ptr *root, + wistd::function &)> workerCallback) + { + wistd::unique_ptr *currentNode = root; while (*currentNode) { - wistd::unique_ptr& node = *currentNode; - if (wcscmp(className, node->className) <= 0) + wistd::unique_ptr &node = *currentNode; + + workerCallback(node); + + // Check if our next node would be a new namespace; if so, then break out + if (node->next && !IsSameNameSpace(node->className, node->next->className)) { break; } + currentNode = &(node->next); } - newApiData->next.reset(currentNode->release()); - currentNode->reset(newApiData.release()); + + return currentNode; } + + static bool IsSameNameSpace(PCWSTR namespaceClass1, PCWSTR namespaceClass2) + { + return (wcsncmp(namespaceClass1, namespaceClass2, GetNameSpaceLength(namespaceClass2) + 1) == 0); + } + + static size_t GetNameSpaceLength(PCWSTR nameSpaceClass) + { + const wchar_t *strAfterNamespace = GetClassStringPointer(nameSpaceClass); + return (strAfterNamespace ? (strAfterNamespace - nameSpaceClass) : wcslen(nameSpaceClass)); + } + + static const wchar_t *GetClassStringPointer(PCWSTR nameSpaceClass) + { + // Note: Usage of wcsrchr can cause build errors in some components, so we implement a way of + // getting the pointer to the 'class' portion of the string ourselves. + int retIndex = 0; + while (nameSpaceClass[retIndex] != '\0') + { + retIndex++; + } + while (retIndex > 0 && nameSpaceClass[retIndex] != '.') + { + retIndex--; + } + return (retIndex != 0 ? &(nameSpaceClass[retIndex]) : nullptr); + } + + wistd::unique_ptr m_root; + wil::srwlock m_lock; + }; + + public: + // Initializes an entry that holds the className.apiName, along with a counter for that className.apiName. + // The counterReference passed to this should later be passed to LogApiInfo. + // + // A separate entry will be created for each apiName that has a distinct specialization value. + // + // This function only needs to be called once for each API, although it doesn't hurt if it gets called more + // than once. + // + // The apiName, className, and specialization parameters should be compile time constants. specialization + // can be null. + DEFINE_EVENT_METHOD(InitApiData) + (PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, volatile long *counterReference) + { + // TODO: Validate that apiName and className are a compile-time constants; validate that specialization + // is either compile-time constant or nullptr; validate that counterReference points to static variable. + // Can do this by making sure address is <= (GetModuleHandle() + DLL size). + m_apiDataList.Insert(className, apiName, specialization, counterReference); } - // For each distinct namespace, calls the provided flushCallback function. - // After returning, it will have deleted all ApiData elements, and zeroed the *counterReference stored in each ApiData. - void Flush(wistd::function flushCallback) + // Fires a telemetry event that contains the method call apiName that has been logged by the component, + // since the last FireEvent() call, or since the component was loaded. + DEFINE_EVENT_METHOD(FireEvent)() { - wistd::unique_ptr root; - if (m_root) - { - auto lock = m_lock.lock_exclusive(); - root.swap(m_root); - } - - while (root) - { - // First find the number of characters we need to allocate for each string, and the number of items in the counter array to allocate - size_t totalApiListLength = 1; // Init to 1 to account for null terminator - size_t totalSpecializationsLength = 1; // Init to 1 to account for null terminator - UINT16 numCounts = 0; - - ProcessSingleNamespace(&root, [&](wistd::unique_ptr& node) { - // Get the length needed for the class string - const wchar_t* strAfterNamespace = GetClassStringPointer(node->className); - size_t classStrLen = wcslen(strAfterNamespace ? strAfterNamespace : node->className); - - totalApiListLength += (classStrLen + wcslen(node->apiName) + 1); // We add 1 to account for the comma delimiter - if (node->specialization) - { - totalSpecializationsLength += strlen(node->specialization) + 1; // We add 1 to account for the comma delimiter - } - else - { - totalSpecializationsLength += 2; // '-' plus comma delimiter - } - numCounts++; - }); - - // Fill arrays with the API data, and then pass it to the callback function - wistd::unique_ptr apiList(new (std::nothrow) wchar_t[totalApiListLength]); - wistd::unique_ptr specializationList(new (std::nothrow) char[totalSpecializationsLength]); - wistd::unique_ptr countArray(new (std::nothrow) UINT32[numCounts]); - size_t nameSpaceLength = GetNameSpaceLength(root->className) + 1; - wistd::unique_ptr nameSpace(new (std::nothrow) wchar_t[nameSpaceLength]); - if (!apiList || !specializationList || !countArray || !nameSpace) + m_apiDataList.Flush([](PCWSTR nameSpace, PCWSTR apiList, PCSTR specializationList, UINT32 *countArray, + UINT16 numCounters) { + if (::wil::details::IsDebuggerPresent()) { - return; - } - - ZeroMemory(apiList.get(), totalApiListLength * sizeof(wchar_t)); - ZeroMemory(specializationList.get(), totalSpecializationsLength * sizeof(char)); - ZeroMemory(countArray.get(), numCounts * sizeof(UINT32)); - ZeroMemory(nameSpace.get(), nameSpaceLength * sizeof(wchar_t)); - - StringCchCopyNW(nameSpace.get(), STRSAFE_MAX_CCH, root->className, nameSpaceLength - 1); - - int countArrayIndex = 0; - - wistd::unique_ptr* lastNamespaceNode = ProcessSingleNamespace(&root, [&](wistd::unique_ptr& node) { - countArray[countArrayIndex] = static_cast(::InterlockedExchangeNoFence(node->counterReference, 0)); - - // Prepend the portion of the apiName group string that's after the '.'. So for example, if the - // className is "Windows.System.Launcher", then we prepend "Launcher." to the apiName string. - const wchar_t* strAfterNamespace = GetClassStringPointer(node->className); - if (strAfterNamespace) - { - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, strAfterNamespace + 1)); - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L".")); - } - - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, node->apiName)); - if (node->specialization) - { - FAIL_FAST_IF( - strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != - 0); - } - else - { - FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0); - } - - if (countArrayIndex != (numCounts - 1)) - { - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L",")); - FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0); - } - - countArrayIndex++; - }); - - // Call the callback function with the data we've collected for this namespace - flushCallback(nameSpace.get(), apiList.get(), specializationList.get(), countArray.get(), numCounts); - - if (*lastNamespaceNode) - { - // Delete everything from the current root to the lastNamespaceNode - // (inclusive), considering the possibility that they are the same. Continue - // processing from the node following lastNamespaceNode, if any. root will - // be made to point to that. - auto newRoot = wistd::move((*lastNamespaceNode)->next); - const auto toDelete = wistd::move(root); - root = wistd::move(newRoot); + TraceLoggingWrite(Provider(), "ApiCallCountsWithDebuggerPresent", + TraceLoggingValue(nameSpace, "Namespace"), + TraceLoggingValue(apiList, "ApiDataList"), + TraceLoggingValue(specializationList, "CustomList"), + TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); } else { - root.reset(); + TraceLoggingWrite(Provider(), "ApiCallCounts", TraceLoggingValue(nameSpace, "Namespace"), + TraceLoggingValue(apiList, "ApiDataList"), + TraceLoggingValue(specializationList, "CustomList"), + TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), + TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); } - } - } - private: - static wistd::unique_ptr* ProcessSingleNamespace( - wistd::unique_ptr* root, wistd::function&)> workerCallback) - { - wistd::unique_ptr* currentNode = root; - while (*currentNode) + __TRACELOGGING_TEST_HOOK_VERIFY_API_TELEMETRY(nameSpace, apiList, specializationList, countArray, + numCounters); + }); + + if (m_fireEventDelay < c_fireEventDelayLimit) { - wistd::unique_ptr& node = *currentNode; - - workerCallback(node); - - // Check if our next node would be a new namespace; if so, then break out - if (node->next && !IsSameNameSpace(node->className, node->next->className)) + // Double the exponential backoff timer, until it reaches the maximum + m_fireEventDelay *= 2; + if (m_fireEventDelay > c_fireEventDelayLimit) { - break; + m_fireEventDelay = c_fireEventDelayLimit; } - - currentNode = &(node->next); } - return currentNode; + ScheduleFireEventCallback(); } - static bool IsSameNameSpace(PCWSTR namespaceClass1, PCWSTR namespaceClass2) + // Used to declare that the component will handle calling FireEvent() in its own suspend handler. + // This optimizes the frequency at which the event will be fired. + DEFINE_EVENT_METHOD(UsingOwnSuspendHandler)() { - return (wcsncmp(namespaceClass1, namespaceClass2, GetNameSpaceLength(namespaceClass2) + 1) == 0); + m_fireEventDelay = c_fireEventDelayLimit; + ScheduleFireEventCallback(); } - static size_t GetNameSpaceLength(PCWSTR nameSpaceClass) + private: + void Initialize() WI_NOEXCEPT override { - const wchar_t* strAfterNamespace = GetClassStringPointer(nameSpaceClass); - return (strAfterNamespace ? (strAfterNamespace - nameSpaceClass) : wcslen(nameSpaceClass)); - } - - static const wchar_t* GetClassStringPointer(PCWSTR nameSpaceClass) - { - // Note: Usage of wcsrchr can cause build errors in some components, so we implement a way of getting the pointer - // to the 'class' portion of the string ourselves. - int retIndex = 0; - while (nameSpaceClass[retIndex] != '\0') - { - retIndex++; - } - while (retIndex > 0 && nameSpaceClass[retIndex] != '.') - { - retIndex--; - } - return (retIndex != 0 ? &(nameSpaceClass[retIndex]) : nullptr); - } - - wistd::unique_ptr m_root; - wil::srwlock m_lock; - }; - - public: - // Initializes an entry that holds the className.apiName, along with a counter for that className.apiName. - // The counterReference passed to this should later be passed to LogApiInfo. - // - // A separate entry will be created for each apiName that has a distinct specialization value. - // - // This function only needs to be called once for each API, although it doesn't hurt if it gets called more than once. - // - // The apiName, className, and specialization parameters should be compile time constants. specialization can be null. - DEFINE_EVENT_METHOD(InitApiData) - (PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, volatile long* counterReference) - { - // TODO: Validate that apiName and className are a compile-time constants; validate that specialization is - // either compile-time constant or nullptr; validate that counterReference points to static variable. - // Can do this by making sure address is <= (GetModuleHandle() + DLL size). - m_apiDataList.Insert(className, apiName, specialization, counterReference); - } - - // Fires a telemetry event that contains the method call apiName that has been logged by the component, - // since the last FireEvent() call, or since the component was loaded. - DEFINE_EVENT_METHOD(FireEvent)() - { - m_apiDataList.Flush([](PCWSTR nameSpace, PCWSTR apiList, PCSTR specializationList, UINT32* countArray, UINT16 numCounters) { - if (::wil::details::IsDebuggerPresent()) - { - TraceLoggingWrite( - Provider(), - "ApiCallCountsWithDebuggerPresent", - TraceLoggingValue(nameSpace, "Namespace"), - TraceLoggingValue(apiList, "ApiDataList"), - TraceLoggingValue(specializationList, "CustomList"), - TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); - } - else - { - TraceLoggingWrite( - Provider(), - "ApiCallCounts", - TraceLoggingValue(nameSpace, "Namespace"), - TraceLoggingValue(apiList, "ApiDataList"), - TraceLoggingValue(specializationList, "CustomList"), - TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), - TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); - } - - __TRACELOGGING_TEST_HOOK_VERIFY_API_TELEMETRY(nameSpace, apiList, specializationList, countArray, numCounters); - }); - - if (m_fireEventDelay < c_fireEventDelayLimit) - { - // Double the exponential backoff timer, until it reaches the maximum - m_fireEventDelay *= 2; - if (m_fireEventDelay > c_fireEventDelayLimit) - { - m_fireEventDelay = c_fireEventDelayLimit; - } - } - - ScheduleFireEventCallback(); - } - - // Used to declare that the component will handle calling FireEvent() in its own suspend handler. - // This optimizes the frequency at which the event will be fired. - DEFINE_EVENT_METHOD(UsingOwnSuspendHandler)() - { - m_fireEventDelay = c_fireEventDelayLimit; - ScheduleFireEventCallback(); - } - - private: - void Initialize() WI_NOEXCEPT override - { #ifdef WIL_API_TELEMETRY_SUSPEND_HANDLER - m_fireEventDelay = c_fireEventDelayLimit; + m_fireEventDelay = c_fireEventDelayLimit; - PPSM_APPSTATE_REGISTRATION psmReg; - BOOLEAN quiesced; - PsmRegisterAppStateChangeNotification( - [](BOOLEAN quiesced, PVOID, HANDLE) { - if (quiesced) - { - FireEvent(); - } - }, - StateChangeCategoryApplication, - 0, - nullptr, - &quiesced, - &psmReg); + PPSM_APPSTATE_REGISTRATION psmReg; + BOOLEAN quiesced; + PsmRegisterAppStateChangeNotification( + [](BOOLEAN quiesced, PVOID, HANDLE) { + if (quiesced) + { + FireEvent(); + } + }, + StateChangeCategoryApplication, 0, nullptr, &quiesced, &psmReg); #else - m_fireEventDelay = __TRACELOGGING_TEST_HOOK_API_TELEMETRY_EVENT_DELAY_MS; + m_fireEventDelay = __TRACELOGGING_TEST_HOOK_API_TELEMETRY_EVENT_DELAY_MS; #endif - m_fireEventThreadPoolTimer.reset(::CreateThreadpoolTimer(&FireEventCallback, nullptr, nullptr)); - ScheduleFireEventCallback(); - } - - static void __stdcall FireEventCallback(PTP_CALLBACK_INSTANCE, PVOID, PTP_TIMER) - { - FireEvent(); - } - - ~ApiTelemetryLogger() WI_NOEXCEPT override - { - FireEvent(); - - // release handle to thread pool timer instead of its destructor being call, if process is being terminated and dll is - // not being unloaded dynamically destruction of threadpool timer is considered invalid during process termination - if (ProcessShutdownInProgress()) - { - m_fireEventThreadPoolTimer.release(); + m_fireEventThreadPoolTimer.reset(::CreateThreadpoolTimer(&FireEventCallback, nullptr, nullptr)); + ScheduleFireEventCallback(); } - } - void ScheduleFireEventCallback() - { - // do not schedule thread pool timer callback, if process is being terminated and dll is not being unloaded dynamically - if (m_fireEventThreadPoolTimer && !ProcessShutdownInProgress()) + static void __stdcall FireEventCallback(PTP_CALLBACK_INSTANCE, PVOID, PTP_TIMER) { - // Note this will override any pending scheduled callback - FILETIME dueTime{}; - *reinterpret_cast(&dueTime) = -static_cast(m_fireEventDelay) * 10000; - SetThreadpoolTimer(m_fireEventThreadPoolTimer.get(), &dueTime, 0, 0); + FireEvent(); } - } - ApiDataList m_apiDataList; - wil::unique_threadpool_timer m_fireEventThreadPoolTimer; + ~ApiTelemetryLogger() WI_NOEXCEPT override + { + FireEvent(); - // The timer used to determine when to fire the next telemetry event (when it's fired based on a timer). - UINT m_fireEventDelay{}; - DWORD const c_fireEventDelayLimit = 20 * 60 * 1000; // 20 minutes - }; -} // namespace details -/// @endcond + // release handle to thread pool timer instead of its destructor being call, if process is being + // terminated and dll is not being unloaded dynamically destruction of threadpool timer is considered + // invalid during process termination + if (ProcessShutdownInProgress()) + { + m_fireEventThreadPoolTimer.release(); + } + } + + void ScheduleFireEventCallback() + { + // do not schedule thread pool timer callback, if process is being terminated and dll is not being + // unloaded dynamically + if (m_fireEventThreadPoolTimer && !ProcessShutdownInProgress()) + { + // Note this will override any pending scheduled callback + FILETIME dueTime{}; + *reinterpret_cast(&dueTime) = -static_cast(m_fireEventDelay) * 10000; + SetThreadpoolTimer(m_fireEventThreadPoolTimer.get(), &dueTime, 0, 0); + } + } + + ApiDataList m_apiDataList; + wil::unique_threadpool_timer m_fireEventThreadPoolTimer; + + // The timer used to determine when to fire the next telemetry event (when it's fired based on a timer). + UINT m_fireEventDelay{}; + DWORD const c_fireEventDelayLimit = 20 * 60 * 1000; // 20 minutes + }; + } // namespace details + /// @endcond } // namespace wil // Insert WI_LOG_API_USE near the top of a WinRT method to log that a method was called. @@ -6661,10 +4999,12 @@ namespace details // - WI_LOG_API_USE(L"LaunchUriAsync", "PointA"); // // If the class name can't be obtained at runtime, or if instrumenting a non-WinRT API, use the below macro, -// and pass the fully qualified class name (in the case of WinRT), or a string identifying the group of the non-WinRT API: +// and pass the fully qualified class name (in the case of WinRT), or a string identifying the group of the non-WinRT +// API: // - WI_LOG_CLASS_API_USE(RuntimeClass_Windows_System_Launcher, L"LaunchUriAsync"); // -// Note: If the component can have a suspend handler, the following line should be added before including TraceLogging.h: +// Note: If the component can have a suspend handler, the following line should be added before including +// TraceLogging.h: // - #define WIL_API_TELEMETRY_SUSPEND_HANDLER // This will optimize the component's ability to upload telemetry, as it will upload on suspend. It will also disable // frequent telemetry upload early in process execution. @@ -6679,21 +5019,23 @@ namespace details // Adding this code snippet ensures that during process termination, thread pool timer // destructor or SetThreadPoolTimer methods are not called, because they are invalid to call // when dll is not getting dynamically unloaded. Skipping this code block will result in a continuable -// exception being thrown if process is getting terminated and dll in which ApiTelemetryLogger is not getting dynamically -// unloaded. For more details about lpReserved parameter, please refer to MSDN. +// exception being thrown if process is getting terminated and dll in which ApiTelemetryLogger is not getting +// dynamically unloaded. For more details about lpReserved parameter, please refer to MSDN. /// @cond -#define __WI_LOG_CLASS_API_USE3(className, apiName, specialization) \ - do \ - { \ - static volatile long __wil_apiCallCounter = 0; \ - if (1 == ::InterlockedIncrementNoFence(&__wil_apiCallCounter)) \ - { \ - ::wil::details::ApiTelemetryLogger::InitApiData(className, apiName, specialization, &__wil_apiCallCounter); \ - } \ +#define __WI_LOG_CLASS_API_USE3(className, apiName, specialization) \ + do \ + { \ + static volatile long __wil_apiCallCounter = 0; \ + if (1 == ::InterlockedIncrementNoFence(&__wil_apiCallCounter)) \ + { \ + ::wil::details::ApiTelemetryLogger::InitApiData(className, apiName, specialization, \ + &__wil_apiCallCounter); \ + } \ } while (0, 0) #define __WI_LOG_CLASS_API_USE2(className, apiName) __WI_LOG_CLASS_API_USE3(className, apiName, nullptr) -#define __WI_LOG_API_USE2(apiName, specialization) __WI_LOG_CLASS_API_USE3(InternalGetRuntimeClassName(), apiName, specialization) +#define __WI_LOG_API_USE2(apiName, specialization) \ + __WI_LOG_CLASS_API_USE3(InternalGetRuntimeClassName(), apiName, specialization) #define __WI_LOG_API_USE1(apiName) __WI_LOG_CLASS_API_USE3(InternalGetRuntimeClassName(), apiName, nullptr) /// @endcond diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com.h index ff91aa0..7ce9cd7 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com.h @@ -13,11 +13,11 @@ #ifndef __WIL_COM_INCLUDED #define __WIL_COM_INCLUDED -#include -#include +#include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available #include "result.h" #include "win32_helpers.h" -#include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available +#include +#include #if WIL_USE_STL && WI_HAS_INCLUDE(, 1) // Tuple is C++11... assume available #include @@ -30,702 +30,527 @@ /// @cond namespace Microsoft { -namespace WRL -{ - template - class ComPtr; -} + namespace WRL + { + template class ComPtr; + } } // namespace Microsoft /// @endcond namespace wil { -/// @cond -namespace details -{ - // We can't directly use wistd::is_convertible as it returns TRUE for an ambiguous conversion. - // Adding is_abstract to the mix, enables us to allow conversion for interfaces, but deny it for - // classes (where the multiple inheritance causes ambiguity). - // NOTE: I've reached out to vcsig on this topic and it turns out that __is_convertible_to should NEVER - // return true for ambiguous conversions. This was a bug in our compiler that has since been fixed. - // Eventually, once that fix propagates we can move to a more efficient __is_convertible_to without - // the added complexity. - template - struct is_com_convertible - : wistd::bool_constant<__is_convertible_to(TFrom, TTo) && (__is_abstract(TFrom) || wistd::is_same::value)> + /// @cond + namespace details { - }; - - using tag_com_query = wistd::integral_constant; - using tag_try_com_query = wistd::integral_constant; - using tag_com_copy = wistd::integral_constant; - using tag_try_com_copy = wistd::integral_constant; - - class default_query_policy - { - public: - template - inline static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result) + // We can't directly use wistd::is_convertible as it returns TRUE for an ambiguous conversion. + // Adding is_abstract to the mix, enables us to allow conversion for interfaces, but deny it for + // classes (where the multiple inheritance causes ambiguity). + // NOTE: I've reached out to vcsig on this topic and it turns out that __is_convertible_to should NEVER + // return true for ambiguous conversions. This was a bug in our compiler that has since been fixed. + // Eventually, once that fix propagates we can move to a more efficient __is_convertible_to without + // the added complexity. + template + struct is_com_convertible : wistd::bool_constant<__is_convertible_to(TFrom, TTo) && + (__is_abstract(TFrom) || wistd::is_same::value)> { - return ptr->QueryInterface(riid, result); - } + }; - template - inline static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result) + using tag_com_query = wistd::integral_constant; + using tag_try_com_query = wistd::integral_constant; + using tag_com_copy = wistd::integral_constant; + using tag_try_com_copy = wistd::integral_constant; + + class default_query_policy { - return query_dispatch(ptr, typename details::is_com_convertible::type(), result); - } - - private: - template - inline static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible - { - *result = ptr; - (*result)->AddRef(); - return S_OK; - } - - template - inline static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible - { - auto hr = ptr->QueryInterface(IID_PPV_ARGS(result)); - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - return hr; - } - }; - - template - struct query_policy_helper - { - using type = default_query_policy; - }; - - class weak_query_policy - { - public: - inline static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result) - { - WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference"); - *result = nullptr; - - IInspectable* temp; - HRESULT hr = ptr->Resolve(__uuidof(IInspectable), &temp); - if (SUCCEEDED(hr)) + public: + template inline static HRESULT query(_In_ T *ptr, REFIID riid, _COM_Outptr_ void **result) { - if (temp == nullptr) - { - return E_NOT_SET; - } - hr = temp->QueryInterface(riid, result); + return ptr->QueryInterface(riid, result); + } + + template + inline static HRESULT query(_In_ T *ptr, _COM_Outptr_ TResult **result) + { + return query_dispatch(ptr, typename details::is_com_convertible::type(), result); + } + + private: + template + inline static HRESULT query_dispatch(_In_ T *ptr, wistd::true_type, + _COM_Outptr_ TResult **result) // convertible + { + *result = ptr; + (*result)->AddRef(); + return S_OK; + } + + template + inline static HRESULT query_dispatch(_In_ T *ptr, wistd::false_type, + _COM_Outptr_ TResult **result) // not convertible + { + auto hr = ptr->QueryInterface(IID_PPV_ARGS(result)); __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - temp->Release(); + return hr; } + }; - return hr; - } - - template - inline static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result) + template struct query_policy_helper { - static_assert(!wistd::is_same::value, "Cannot resolve a weak reference to IWeakReference"); - return query_dispatch(ptr, wistd::is_base_of(), result); - } + using type = default_query_policy; + }; - private: - template - static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::true_type, _COM_Outptr_ TResult** result) + class weak_query_policy { - auto hr = ptr->Resolve(__uuidof(TResult), reinterpret_cast(result)); - if (SUCCEEDED(hr) && (*result == nullptr)) + public: + inline static HRESULT query(_In_ IWeakReference *ptr, REFIID riid, _COM_Outptr_ void **result) { - hr = E_NOT_SET; + WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference"); + *result = nullptr; + + IInspectable *temp; + HRESULT hr = ptr->Resolve(__uuidof(IInspectable), &temp); + if (SUCCEEDED(hr)) + { + if (temp == nullptr) + { + return E_NOT_SET; + } + hr = temp->QueryInterface(riid, result); + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); + temp->Release(); + } + + return hr; } - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - return hr; - } - template - static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::false_type, _COM_Outptr_ TResult** result) + template + inline static HRESULT query(_In_ IWeakReference *ptr, _COM_Outptr_ TResult **result) + { + static_assert(!wistd::is_same::value, + "Cannot resolve a weak reference to IWeakReference"); + return query_dispatch(ptr, wistd::is_base_of(), result); + } + + private: + template + static HRESULT query_dispatch(_In_ IWeakReference *ptr, wistd::true_type, _COM_Outptr_ TResult **result) + { + auto hr = ptr->Resolve(__uuidof(TResult), reinterpret_cast(result)); + if (SUCCEEDED(hr) && (*result == nullptr)) + { + hr = E_NOT_SET; + } + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); + return hr; + } + + template + static HRESULT query_dispatch(_In_ IWeakReference *ptr, wistd::false_type, _COM_Outptr_ TResult **result) + { + return query(ptr, IID_PPV_ARGS(result)); + } + }; + + template <> struct query_policy_helper { - return query(ptr, IID_PPV_ARGS(result)); - } - }; - - template <> - struct query_policy_helper - { - using type = weak_query_policy; - }; + using type = weak_query_policy; + }; #if (NTDDI_VERSION >= NTDDI_WINBLUE) - class agile_query_policy - { - public: - inline static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result) + class agile_query_policy { - WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference"); - auto hr = ptr->Resolve(riid, result); - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); // IAgileReference::Resolve not annotated correctly - return hr; - } + public: + inline static HRESULT query(_In_ IAgileReference *ptr, REFIID riid, _COM_Outptr_ void **result) + { + WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference"); + auto hr = ptr->Resolve(riid, result); + __analysis_assume(SUCCEEDED(hr) || + (*result == nullptr)); // IAgileReference::Resolve not annotated correctly + return hr; + } - template - static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result) + template static HRESULT query(_In_ IAgileReference *ptr, _COM_Outptr_ TResult **result) + { + static_assert(!wistd::is_same::value, + "Cannot resolve a agile reference to IAgileReference"); + return query(ptr, __uuidof(TResult), reinterpret_cast(result)); + } + }; + + template <> struct query_policy_helper { - static_assert(!wistd::is_same::value, "Cannot resolve a agile reference to IAgileReference"); - return query(ptr, __uuidof(TResult), reinterpret_cast(result)); - } - }; - - template <> - struct query_policy_helper - { - using type = agile_query_policy; - }; + using type = agile_query_policy; + }; #endif - template - using query_policy_t = typename query_policy_helper::type>::type; + template + using query_policy_t = typename query_policy_helper::type>::type; -} // namespace details -/// @endcond + } // namespace details + /// @endcond -//! Represents the base template type that implements com_ptr, com_weak_ref, and com_agile_ref. -//! See @ref page_comptr for more background. See @ref page_query for more information on querying with WIL. -//! @tparam T Represents the type being held by the com_ptr_t. -//! For com_ptr, this will always be the interface being represented. For com_weak_ref, this will always -//! be IWeakReference. For com_agile_ref, this will always be IAgileReference. -//! @tparam err_policy Represents the error policy for the class (error codes, exceptions, or fail fast; see @ref page_errors) -template -class com_ptr_t -{ -private: - using element_type_reference = typename wistd::add_lvalue_reference::type; - using query_policy = details::query_policy_t; - -public: - //! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors). - using result = typename err_policy::result; - //! The template type `T` being held by the com_ptr_t. - using element_type = T; - //! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns). - using pointer = T*; - - //! @name Constructors - //! @{ - - //! Default constructor (holds nullptr). - com_ptr_t() WI_NOEXCEPT : m_ptr(nullptr) + //! Represents the base template type that implements com_ptr, com_weak_ref, and com_agile_ref. + //! See @ref page_comptr for more background. See @ref page_query for more information on querying with WIL. + //! @tparam T Represents the type being held by the com_ptr_t. + //! For com_ptr, this will always be the interface being represented. For com_weak_ref, + //! this will always be IWeakReference. For com_agile_ref, this will always be + //! IAgileReference. + //! @tparam err_policy Represents the error policy for the class (error codes, exceptions, or fail fast; see + //! @ref page_errors) + template class com_ptr_t { - } + private: + using element_type_reference = typename wistd::add_lvalue_reference::type; + using query_policy = details::query_policy_t; - //! Implicit construction from nullptr_t (holds nullptr). - com_ptr_t(wistd::nullptr_t) WI_NOEXCEPT : com_ptr_t() - { - } + public: + //! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors). + using result = typename err_policy::result; + //! The template type `T` being held by the com_ptr_t. + using element_type = T; + //! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns). + using pointer = T *; - //! Implicit construction from a compatible raw interface pointer (AddRef's the parameter). - com_ptr_t(pointer ptr) WI_NOEXCEPT : m_ptr(ptr) - { - if (m_ptr) + //! @name Constructors + //! @{ + + //! Default constructor (holds nullptr). + com_ptr_t() WI_NOEXCEPT : m_ptr(nullptr) { - m_ptr->AddRef(); } - } - //! Copy-construction from a like `com_ptr_t` (copies and AddRef's the parameter). - com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : com_ptr_t(other.get()) - { - } - - //! Copy-construction from a convertible `com_ptr_t` (copies and AddRef's the parameter). - template > - com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : com_ptr_t(static_cast(other.get())) - { - } - - //! Move construction from a like `com_ptr_t` (avoids AddRef/Release by moving from the parameter). - com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : m_ptr(other.detach()) - { - } - - //! Move construction from a compatible `com_ptr_t` (avoids AddRef/Release by moving from the parameter). - template > - com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : m_ptr(other.detach()) - { - } - //! @} - - //! Destructor (releases the pointer). - ~com_ptr_t() WI_NOEXCEPT - { - if (m_ptr) + //! Implicit construction from nullptr_t (holds nullptr). + com_ptr_t(wistd::nullptr_t) WI_NOEXCEPT : com_ptr_t() { - m_ptr->Release(); } - } - //! @name Assignment operators - //! @{ - - //! Assign to nullptr (releases the current pointer, holds nullptr). - com_ptr_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - return *this; - } - - //! Assign a compatible raw interface pointer (releases current pointer, copies and AddRef's the parameter). - com_ptr_t& operator=(pointer other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other; - if (m_ptr) + //! Implicit construction from a compatible raw interface pointer (AddRef's the parameter). + com_ptr_t(pointer ptr) WI_NOEXCEPT : m_ptr(ptr) { - m_ptr->AddRef(); + if (m_ptr) + { + m_ptr->AddRef(); + } } - if (ptr) + + //! Copy-construction from a like `com_ptr_t` (copies and AddRef's the parameter). + com_ptr_t(const com_ptr_t &other) WI_NOEXCEPT : com_ptr_t(other.get()) { - ptr->Release(); } - return *this; - } - //! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). - com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT - { - return operator=(other.get()); - } - - //! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). - template > - com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT - { - return operator=(static_cast(other.get())); - } - - //! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the parameter). - com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT - { - attach(other.detach()); - return *this; - } - - //! Move assignment from a compatible `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving from the - //! parameter). - template > - com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT - { - attach(other.detach()); - return *this; - } - //! @} - - //! @name Modifiers - //! @{ - - //! Swap pointers with an another named com_ptr_t object. - template - void swap(com_ptr_t& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other.m_ptr; - other.m_ptr = ptr; - } - - //! Swap pointers with a rvalue reference to another com_ptr_t object. - template - void swap(com_ptr_t&& other) WI_NOEXCEPT - { - swap(other); - } - - //! Releases the pointer and sets it to nullptr. - void reset() WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = nullptr; - if (ptr) + //! Copy-construction from a convertible `com_ptr_t` (copies and AddRef's the parameter). + template > + com_ptr_t(const com_ptr_t &other) WI_NOEXCEPT : com_ptr_t(static_cast(other.get())) { - ptr->Release(); } - } - //! Releases the pointer and sets it to nullptr. - void reset(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - } - - //! Takes ownership of a compatible raw interface pointer (releases pointer, copies but DOES NOT AddRef the parameter). - void attach(pointer other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other; - if (ptr) + //! Move construction from a like `com_ptr_t` (avoids AddRef/Release by moving from the parameter). + com_ptr_t(com_ptr_t &&other) WI_NOEXCEPT : m_ptr(other.detach()) { - ULONG ref = ptr->Release(); - WI_ASSERT_MSG(((other != ptr) || (ref > 0)), "Bug: Attaching the same already assigned, destructed pointer"); } - } - //! Relinquishes ownership and returns the internal interface pointer (DOES NOT release the detached pointer, sets class - //! pointer to null). - WI_NODISCARD pointer detach() WI_NOEXCEPT - { - auto temp = m_ptr; - m_ptr = nullptr; - return temp; - } - - //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). - //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that - //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. - //! @see addressof - //! ~~~~ - //! STDAPI GetMuffin(IMuffin **muffin); - //! wil::com_ptr myMuffin; - //! THROW_IF_FAILED(GetMuffin(myMuffin.put())); - //! ~~~~ - pointer* put() WI_NOEXCEPT - { - reset(); - return &m_ptr; - } - - //! Returns the address of the internal pointer casted to void** (releases ownership of the pointer BEFORE returning the - //! address). - //! @see put - void** put_void() WI_NOEXCEPT - { - return reinterpret_cast(put()); - } - - //! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE returning the address). - //! @see put - ::IUnknown** put_unknown() WI_NOEXCEPT - { - return reinterpret_cast<::IUnknown**>(put()); - } - - //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). - //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that - //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. Since this behavior is - //! not always immediately apparent, prefer to scope variables as close to use as possible (generally avoiding use of the same - //! com_ptr variable in successive calls to receive an output interface). - //! @see addressof - pointer* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Returns the address of the internal pointer (does not release the pointer; should not be used for `_Out_` parameters) - pointer* addressof() WI_NOEXCEPT - { - return &m_ptr; - } - //! @} - - //! @name Inspection - //! @{ - - //! Returns the address of the const internal pointer (does not release the pointer) - WI_NODISCARD const pointer* addressof() const WI_NOEXCEPT - { - return &m_ptr; - } - - //! Returns 'true' if the pointer is assigned (NOT nullptr) - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != nullptr); - } - - //! Returns the pointer - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return m_ptr; - } - - //! Allows direct calls against the pointer (AV on internal nullptr) - WI_NODISCARD pointer operator->() const WI_NOEXCEPT - { - return m_ptr; - } - - //! Dereferences the pointer (AV on internal nullptr) - WI_NODISCARD element_type_reference operator*() const WI_NOEXCEPT - { - return *m_ptr; - } - //! @} - - //! @name Query helpers - //! * Retrieves the requested interface - //! * AV if the pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information - //! @{ - - //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.query();`. - //! See @ref page_query for more information. - //! - //! This method is the primary method that should be used to query a com_ptr in exception-based or fail-fast based code. - //! Error-code returning code should use @ref query_to so that the returned HRESULT can be examined. In the following - //! examples, `m_ptr` is an exception-based or fail-fast based com_ptr, com_weak_ref, or com_agile_ref: - //! ~~~~ - //! auto foo = ptr.query(); - //! foo->Method1(); - //! foo->Method2(); - //! ~~~~ - //! For simple single-method calls, this method allows removing the temporary that holds the com_ptr: - //! ~~~~ - //! ptr.query()->Method1(); - //! ~~~~ - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer is guaranteed not null. The returned - //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the - //! pointer being queried (exception based or fail-fast). - template - WI_NODISCARD inline com_ptr_t query() const - { - static_assert(wistd::is_same::value, "query requires exceptions or fail fast; use try_query or query_to"); - return com_ptr_t(m_ptr, details::tag_com_query()); - } - - //! Query for the interface of the given out parameter `U`: `ptr.query_to(&foo);`. - //! See @ref page_query for more information. - //! - //! For fail-fast and exception-based behavior this routine should primarily be used to write to out parameters and @ref query - //! should be used to perform most queries. For error-code based code, this routine is the primary method that should be used - //! to query a com_ptr. - //! - //! Error-code based samples: - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // simple query example: - //! wil::com_ptr_nothrow foo; - //! RETURN_IF_FAILED(m_ptr.query_to(&foo)); - //! foo->FooMethod1(); - //! - //! // output parameter example: - //! HRESULT GetFoo(_COM_Outptr_ IFoo** fooPtr) - //! { - //! RETURN_IF_FAILED(m_ptr.query_to(fooPtr)); - //! return S_OK; - //! } - //! ~~~~ - //! Exception or fail-fast samples: - //! ~~~~ - //! // class member being queried - //! wil::com_ptr m_ptr; - //! - //! void GetFoo(_COM_Outptr_ IFoo** fooPtr) - //! { - //! m_ptr.query_to(fooPtr); - //! } - //! ~~~~ - //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need - //! to be specified directly. Rely upon template type deduction to pick up the type from the output - //! parameter. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, - //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the query was - //! successful. Exception-based and fail-fast based classes do not return a value (void). - template - result query_to(_COM_Outptr_ U** ptrResult) const - { - // Prefast cannot see through the error policy + query_policy mapping and as a result fires 6388 and 28196 for this - // function. Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does - // not stop all of the prefast errors from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); -#endif - } - - //! Query for the requested interface using the iid, ppv pattern: `ptr.query_to(riid, ptr);`. - //! See @ref page_query for more information. - //! - //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and - //! void** pointer pattern (like QueryInterface). This pattern should not be used outside of that pattern (through - //! IID_PPV_ARGS) as it is less efficient than the typed version of @ref query_to which can elide the QueryInterface in favor - //! of AddRef when the types are convertible. - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // output parameter example: - //! HRESULT GetFoo(REFIID riid, _COM_Outptr_ void** ptrResult) - //! { - //! RETURN_IF_FAILED(m_ptr.query_to(riid, ptrResult)); - //! return S_OK; - //! } - //! ~~~~ - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, - //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the query was - //! successful. Exception-based and fail-fast based classes do not return a value (void). - result query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const - { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 - // for this function. Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 - // 28196) does not stop the prefast errors from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); -#endif - } - //! @} - - //! @name Try query helpers - //! * Attempts to retrieves the requested interface - //! * AV if the pointer is null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'true' when query was successful - //! - //! See @ref page_query for more information. - //! @{ - - //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` - //! (null result when interface is unsupported). - //! See @ref page_query for more information. - //! - //! This method can be used to query a com_ptr for an interface when it's known that support for that interface is - //! optional (failing the query should not produce an error). The caller must examine the returned pointer to see - //! if it's null before using it: - //! ~~~~ - //! auto foo = ptr.try_query(); - //! if (foo) - //! { - //! foo->Method1(); - //! foo->Method2(); - //! } - //! ~~~~ - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface is - //! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, failfast or - //! error codes) as the pointer being queried. - template - WI_NODISCARD inline com_ptr_t try_query() const - { - return com_ptr_t(m_ptr, details::tag_try_com_query()); - } - - //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was - //! successful (non-null). - //! See @ref page_query for more information. - //! - //! This method can be used to perform a query against a non-null interface when it's known that support for that interface is - //! optional (failing the query should not produce an error). The caller must examine the returned bool before using the - //! returned pointer. - //! ~~~~ - //! wil::com_ptr_nothrow foo; - //! if (ptr.try_query_to(&foo)) - //! { - //! foo->Method1(); - //! foo->Method2(); - //! } - //! ~~~~ - //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do - //! not specify the type directly to the template. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - template - _Success_return_ bool try_query_to(_COM_Outptr_ U** ptrResult) const - { - return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); - } - - //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);`. - //! See @ref page_query for more information. - //! - //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and - //! void** pointer pattern (like QueryInterface). The key distinction is that this routine does not produce an error if the - //! request isn't fulfilled, so it's appropriate for `_COM_Outptr_result_maybenull_` cases. This pattern should not be used - //! outside of that pattern (through IID_PPV_ARGS) as it is less efficient than the typed version of @ref try_query_to which - //! can elide the QueryInterface in favor of AddRef when the types are convertible. The caller must examine the returned bool - //! before using the returned pointer. - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // output parameter example (result may be null): - //! HRESULT GetFoo(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - //! { - //! m_ptr.try_query_to(riid, ptrResult); - //! return S_OK; - //! } - //! ~~~~ - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - _Success_return_ bool try_query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const - { - return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); - } - //! @} - - //! @name Copy helpers - //! * Retrieves the requested interface - //! * Succeeds with null if the pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information. - //! @{ - - //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.copy();` (succeeds and - //! returns a null ptr if the queried pointer is null). - //! See @ref page_query for more information. - //! - //! This method is identical to @ref query with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query it will - //! produce an error for a non-null pointer that does not support the requested interface. - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer will be null ONLY if the pointer being queried is - //! null. The returned `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling - //! form of the pointer being queried (exception based or fail-fast). - template - WI_NODISCARD inline com_ptr_t copy() const - { - static_assert(wistd::is_same::value, "copy requires exceptions or fail fast; use the try_copy or copy_to method"); - return com_ptr_t(m_ptr, details::tag_com_copy()); - } - - //! Query for the interface of the given out parameter `U`: `ptr.copy_to(&foo);` (succeeds and returns null ptr if the - //! queried pointer is null). - //! See @ref page_query for more information. - //! - //! This method is identical to @ref query_to with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will - //! produce an error for a non-null pointer that does not support the requested interface. - //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need - //! to be specified directly. Rely upon template type deduction to pick up the type from the output - //! parameter. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure OR assigned null when the source pointer is null. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, - //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the query was - //! successful. Copying a null value is considered success. Exception-based and fail-fast based classes - //! do not return a value (void). - template - result copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const - { - if (m_ptr) + //! Move construction from a compatible `com_ptr_t` (avoids AddRef/Release by moving from the parameter). + template > + com_ptr_t(com_ptr_t &&other) WI_NOEXCEPT : m_ptr(other.detach()) { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and - // 28196 for this function. Suppression is also not working. Wrapping this entire function in #pragma warning(disable: - // 6388 28196) does not stop the prefast errors from being emitted. + } + //! @} + + //! Destructor (releases the pointer). + ~com_ptr_t() WI_NOEXCEPT + { + if (m_ptr) + { + m_ptr->Release(); + } + } + + //! @name Assignment operators + //! @{ + + //! Assign to nullptr (releases the current pointer, holds nullptr). + com_ptr_t &operator=(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + return *this; + } + + //! Assign a compatible raw interface pointer (releases current pointer, copies and AddRef's the parameter). + com_ptr_t &operator=(pointer other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other; + if (m_ptr) + { + m_ptr->AddRef(); + } + if (ptr) + { + ptr->Release(); + } + return *this; + } + + //! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). + com_ptr_t &operator=(const com_ptr_t &other) WI_NOEXCEPT + { + return operator=(other.get()); + } + + //! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). + template > + com_ptr_t &operator=(const com_ptr_t &other) WI_NOEXCEPT + { + return operator=(static_cast(other.get())); + } + + //! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the + //! parameter). + com_ptr_t &operator=(com_ptr_t &&other) WI_NOEXCEPT + { + attach(other.detach()); + return *this; + } + + //! Move assignment from a compatible `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving + //! from the parameter). + template > + com_ptr_t &operator=(com_ptr_t &&other) WI_NOEXCEPT + { + attach(other.detach()); + return *this; + } + //! @} + + //! @name Modifiers + //! @{ + + //! Swap pointers with an another named com_ptr_t object. + template void swap(com_ptr_t &other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other.m_ptr; + other.m_ptr = ptr; + } + + //! Swap pointers with a rvalue reference to another com_ptr_t object. + template void swap(com_ptr_t &&other) WI_NOEXCEPT + { + swap(other); + } + + //! Releases the pointer and sets it to nullptr. + void reset() WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = nullptr; + if (ptr) + { + ptr->Release(); + } + } + + //! Releases the pointer and sets it to nullptr. + void reset(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + } + + //! Takes ownership of a compatible raw interface pointer (releases pointer, copies but DOES NOT AddRef the + //! parameter). + void attach(pointer other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other; + if (ptr) + { + ULONG ref = ptr->Release(); + WI_ASSERT_MSG(((other != ptr) || (ref > 0)), + "Bug: Attaching the same already assigned, destructed pointer"); + } + } + + //! Relinquishes ownership and returns the internal interface pointer (DOES NOT release the detached pointer, + //! sets class pointer to null). + WI_NODISCARD pointer detach() WI_NOEXCEPT + { + auto temp = m_ptr; + m_ptr = nullptr; + return temp; + } + + //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the + //! address). The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards + //! generally indicate that there is little valid `_Inout_` use of `IInterface**`, making this safe to do under + //! typical use. + //! @see addressof + //! ~~~~ + //! STDAPI GetMuffin(IMuffin **muffin); + //! wil::com_ptr myMuffin; + //! THROW_IF_FAILED(GetMuffin(myMuffin.put())); + //! ~~~~ + pointer *put() WI_NOEXCEPT + { + reset(); + return &m_ptr; + } + + //! Returns the address of the internal pointer casted to void** (releases ownership of the pointer BEFORE + //! returning the address). + //! @see put + void **put_void() WI_NOEXCEPT + { + return reinterpret_cast(put()); + } + + //! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE + //! returning the address). + //! @see put + ::IUnknown **put_unknown() WI_NOEXCEPT + { + return reinterpret_cast<::IUnknown **>(put()); + } + + //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the + //! address). The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards + //! generally indicate that there is little valid `_Inout_` use of `IInterface**`, making this safe to do under + //! typical use. Since this behavior is not always immediately apparent, prefer to scope variables as close to + //! use as possible (generally avoiding use of the same com_ptr variable in successive calls to receive an + //! output interface). + //! @see addressof + pointer *operator&() WI_NOEXCEPT + { + return put(); + } + + //! Returns the address of the internal pointer (does not release the pointer; should not be used for `_Out_` + //! parameters) + pointer *addressof() WI_NOEXCEPT + { + return &m_ptr; + } + //! @} + + //! @name Inspection + //! @{ + + //! Returns the address of the const internal pointer (does not release the pointer) + WI_NODISCARD const pointer *addressof() const WI_NOEXCEPT + { + return &m_ptr; + } + + //! Returns 'true' if the pointer is assigned (NOT nullptr) + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != nullptr); + } + + //! Returns the pointer + WI_NODISCARD pointer get() const WI_NOEXCEPT + { + return m_ptr; + } + + //! Allows direct calls against the pointer (AV on internal nullptr) + WI_NODISCARD pointer operator->() const WI_NOEXCEPT + { + return m_ptr; + } + + //! Dereferences the pointer (AV on internal nullptr) + WI_NODISCARD element_type_reference operator*() const WI_NOEXCEPT + { + return *m_ptr; + } + //! @} + + //! @name Query helpers + //! * Retrieves the requested interface + //! * AV if the pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + + //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = + //! m_ptr.query();`. See @ref page_query for more information. + //! + //! This method is the primary method that should be used to query a com_ptr in exception-based or fail-fast + //! based code. Error-code returning code should use @ref query_to so that the returned HRESULT can be examined. + //! In the following examples, `m_ptr` is an exception-based or fail-fast based com_ptr, com_weak_ref, or + //! com_agile_ref: + //! ~~~~ + //! auto foo = ptr.query(); + //! foo->Method1(); + //! foo->Method2(); + //! ~~~~ + //! For simple single-method calls, this method allows removing the temporary that holds the com_ptr: + //! ~~~~ + //! ptr.query()->Method1(); + //! ~~~~ + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer is guaranteed not null. The returned + //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of + //! the pointer being queried (exception based or fail-fast). + template WI_NODISCARD inline com_ptr_t query() const + { + static_assert(wistd::is_same::value, + "query requires exceptions or fail fast; use try_query or query_to"); + return com_ptr_t(m_ptr, details::tag_com_query()); + } + + //! Query for the interface of the given out parameter `U`: `ptr.query_to(&foo);`. + //! See @ref page_query for more information. + //! + //! For fail-fast and exception-based behavior this routine should primarily be used to write to out parameters + //! and @ref query should be used to perform most queries. For error-code based code, this routine is the + //! primary method that should be used to query a com_ptr. + //! + //! Error-code based samples: + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // simple query example: + //! wil::com_ptr_nothrow foo; + //! RETURN_IF_FAILED(m_ptr.query_to(&foo)); + //! foo->FooMethod1(); + //! + //! // output parameter example: + //! HRESULT GetFoo(_COM_Outptr_ IFoo** fooPtr) + //! { + //! RETURN_IF_FAILED(m_ptr.query_to(fooPtr)); + //! return S_OK; + //! } + //! ~~~~ + //! Exception or fail-fast samples: + //! ~~~~ + //! // class member being queried + //! wil::com_ptr m_ptr; + //! + //! void GetFoo(_COM_Outptr_ IFoo** fooPtr) + //! { + //! m_ptr.query_to(fooPtr); + //! } + //! ~~~~ + //! @tparam U Represents the interface being queried (type of the output parameter). This interface + //! does not need + //! to be specified directly. Rely upon template type deduction to pick up the type from + //! the output parameter. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref + //! com_weak_ref_nothrow, + //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the + //! query was successful. Exception-based and fail-fast based classes do not return a value + //! (void). + template result query_to(_COM_Outptr_ U **ptrResult) const + { + // Prefast cannot see through the error policy + query_policy mapping and as a result fires 6388 and 28196 + // for this function. Suppression is also not working. Wrapping this entire function in #pragma + // warning(disable: 6388 28196) does not stop all of the prefast errors from being emitted. #if defined(_PREFAST_) *ptrResult = nullptr; return err_policy::HResult(E_NOINTERFACE); @@ -733,31 +558,39 @@ public: return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); #endif } - *ptrResult = nullptr; - return err_policy::OK(); - } - //! Query for the requested interface using the iid, ppv pattern: `ptr.copy_to(riid, ptr);`. (succeeds and returns null ptr - //! if the queried pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref query_to method with the exception that it can be used when the pointer is null. When - //! used against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it - //! will produce an error for a non-null pointer that does not support the requested interface. - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure OR assigned null when the source pointer is null. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, - //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the query was - //! successful. Copying a null value is considered success. Exception-based and fail-fast based classes - //! do not return a value (void). - result copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const - { - if (m_ptr) + //! Query for the requested interface using the iid, ppv pattern: `ptr.query_to(riid, ptr);`. + //! See @ref page_query for more information. + //! + //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the + //! REFIID and void** pointer pattern (like QueryInterface). This pattern should not be used outside of that + //! pattern (through IID_PPV_ARGS) as it is less efficient than the typed version of @ref query_to which can + //! elide the QueryInterface in favor of AddRef when the types are convertible. + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // output parameter example: + //! HRESULT GetFoo(REFIID riid, _COM_Outptr_ void** ptrResult) + //! { + //! RETURN_IF_FAILED(m_ptr.query_to(riid, ptrResult)); + //! return S_OK; + //! } + //! ~~~~ + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref + //! com_weak_ref_nothrow, + //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the + //! query was successful. Exception-based and fail-fast based classes do not return a value + //! (void). + result query_to(REFIID riid, _COM_Outptr_ void **ptrResult) const { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and - // 28196 for this function. Suppression is also not working. Wrapping this entire function in #pragma warning(disable: - // 6388 28196) does not stop the prefast errors from being emitted. + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires + // 6388 and 28196 for this function. Suppression is also not working. Wrapping this entire function in + // #pragma warning(disable: 6388 28196) does not stop the prefast errors from being emitted. #if defined(_PREFAST_) *ptrResult = nullptr; return err_policy::HResult(E_NOINTERFACE); @@ -765,496 +598,678 @@ public: return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); #endif } - *ptrResult = nullptr; - return err_policy::OK(); - } - //! @} + //! @} - //! @name Try copy helpers - //! * Attempts to retrieves the requested interface - //! * Successfully produces null if the queried pointer is already null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'false' ONLY when the queried pointer is not null and the requested interface is unsupported - //! - //! See @ref page_query for more information. - //! @{ + //! @name Try query helpers + //! * Attempts to retrieves the requested interface + //! * AV if the pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful + //! + //! See @ref page_query for more information. + //! @{ - //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` - //! (null result when interface is unsupported or queried pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query method with the exception that it can be used when the pointer is null. - //! When used against a null pointer, the returned pointer will always be null and an error will not be produced. - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface was - //! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same error - //! handling policy (exceptions, failfast or error codes) as the pointer being queried. - template - WI_NODISCARD inline com_ptr_t try_copy() const - { - return com_ptr_t(m_ptr, details::tag_try_com_copy()); - } + //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = + //! m_ptr.try_query();` (null result when interface is unsupported). See @ref page_query for more + //! information. + //! + //! This method can be used to query a com_ptr for an interface when it's known that support for that interface + //! is optional (failing the query should not produce an error). The caller must examine the returned pointer + //! to see if it's null before using it: + //! ~~~~ + //! auto foo = ptr.try_query(); + //! if (foo) + //! { + //! foo->Method1(); + //! foo->Method2(); + //! } + //! ~~~~ + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the + //! interface is + //! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, + //! failfast or error codes) as the pointer being queried. + template WI_NODISCARD inline com_ptr_t try_query() const + { + return com_ptr_t(m_ptr, details::tag_try_com_query()); + } - //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was - //! successful (returns `false` if the pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. - //! When used against a null pointer, the returned pointer will be null and the return value will be `false`. - //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do - //! not specify the type directly to the template. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - template - _Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const - { - if (m_ptr) + //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the + //! query was successful (non-null). See @ref page_query for more information. + //! + //! This method can be used to perform a query against a non-null interface when it's known that support for + //! that interface is optional (failing the query should not produce an error). The caller must examine the + //! returned bool before using the returned pointer. + //! ~~~~ + //! wil::com_ptr_nothrow foo; + //! if (ptr.try_query_to(&foo)) + //! { + //! foo->Method1(); + //! foo->Method2(); + //! } + //! ~~~~ + //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out + //! parameter; do + //! not specify the type directly to the template. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is + //! non-null). + template _Success_return_ bool try_query_to(_COM_Outptr_ U **ptrResult) const { return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); } - *ptrResult = nullptr; - return false; - } - //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);` (returns `false` - //! if the pointer is null) - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. - //! When used against a null pointer, the returned pointer will be null and the return value will be `false`. - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null - //! on failure or if the source pointer being queried is null. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). Querying - //! a null pointer will return `false` with a null result. - _Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const - { - if (m_ptr) + //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);`. + //! See @ref page_query for more information. + //! + //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the + //! REFIID and void** pointer pattern (like QueryInterface). The key distinction is that this routine does not + //! produce an error if the request isn't fulfilled, so it's appropriate for `_COM_Outptr_result_maybenull_` + //! cases. This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as it is less + //! efficient than the typed version of @ref try_query_to which can elide the QueryInterface in favor of AddRef + //! when the types are convertible. The caller must examine the returned bool before using the returned + //! pointer. + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // output parameter example (result may be null): + //! HRESULT GetFoo(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + //! { + //! m_ptr.try_query_to(riid, ptrResult); + //! return S_OK; + //! } + //! ~~~~ + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is + //! non-null). + _Success_return_ bool try_query_to(REFIID riid, _COM_Outptr_ void **ptrResult) const { return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); } - *ptrResult = nullptr; - return false; - } - //! @} + //! @} - //! @name WRL compatibility - //! @{ + //! @name Copy helpers + //! * Retrieves the requested interface + //! * Succeeds with null if the pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information. + //! @{ - //! Copy construct from a compatible WRL ComPtr. - template > - com_ptr_t(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT : com_ptr_t(static_cast(other.Get())) - { - } + //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.copy();` + //! (succeeds and returns a null ptr if the queried pointer is null). See @ref page_query for more information. + //! + //! This method is identical to @ref query with the exception that it can be used when the pointer is null. When + //! used against a null pointer, the returned pointer will always be null and an error will not be produced. + //! Like query it will produce an error for a non-null pointer that does not support the requested interface. + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer will be null ONLY if the pointer + //! being queried is + //! null. The returned `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the + //! error handling form of the pointer being queried (exception based or fail-fast). + template WI_NODISCARD inline com_ptr_t copy() const + { + static_assert(wistd::is_same::value, + "copy requires exceptions or fail fast; use the try_copy or copy_to method"); + return com_ptr_t(m_ptr, details::tag_com_copy()); + } - //! Move construct from a compatible WRL ComPtr. - template > - com_ptr_t(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT : m_ptr(other.Detach()) - { - } + //! Query for the interface of the given out parameter `U`: `ptr.copy_to(&foo);` (succeeds and returns null ptr + //! if the queried pointer is null). See @ref page_query for more information. + //! + //! This method is identical to @ref query_to with the exception that it can be used when the pointer is null. + //! When used against a null pointer, the returned pointer will always be null and an error will not be + //! produced. Like query_to it will produce an error for a non-null pointer that does not support the requested + //! interface. + //! @tparam U Represents the interface being queried (type of the output parameter). This interface + //! does not need + //! to be specified directly. Rely upon template type deduction to pick up the type from + //! the output parameter. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure OR assigned null when the source pointer is null. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref + //! com_weak_ref_nothrow, + //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the + //! query was successful. Copying a null value is considered success. Exception-based and + //! fail-fast based classes do not return a value (void). + template result copy_to(_COM_Outptr_result_maybenull_ U **ptrResult) const + { + if (m_ptr) + { + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result + // fires 6388 and 28196 for this function. Suppression is also not working. Wrapping this entire + // function in #pragma warning(disable: 6388 28196) does not stop the prefast errors from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); +#endif + } + *ptrResult = nullptr; + return err_policy::OK(); + } - //! Assign from a compatible WRL ComPtr. - template > - com_ptr_t& operator=(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT - { - return operator=(static_cast(other.Get())); - } + //! Query for the requested interface using the iid, ppv pattern: `ptr.copy_to(riid, ptr);`. (succeeds and + //! returns null ptr if the queried pointer is null). See @ref page_query for more information. + //! + //! Identical to the corresponding @ref query_to method with the exception that it can be used when the pointer + //! is null. When used against a null pointer, the returned pointer will always be null and an error will not + //! be produced. Like query_to it will produce an error for a non-null pointer that does not support the + //! requested interface. + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure OR assigned null when the source pointer is null. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref + //! com_weak_ref_nothrow, + //! @ref com_agile_ref_nothrow) this method returns an `HRESULT` indicating whether the + //! query was successful. Copying a null value is considered success. Exception-based and + //! fail-fast based classes do not return a value (void). + result copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) const + { + if (m_ptr) + { + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result + // fires 6388 and 28196 for this function. Suppression is also not working. Wrapping this entire + // function in #pragma warning(disable: 6388 28196) does not stop the prefast errors from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); +#endif + } + *ptrResult = nullptr; + return err_policy::OK(); + } + //! @} - //! Move assign from a compatible WRL ComPtr. - template > - com_ptr_t& operator=(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT - { - attach(other.Detach()); - return *this; - } + //! @name Try copy helpers + //! * Attempts to retrieves the requested interface + //! * Successfully produces null if the queried pointer is already null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'false' ONLY when the queried pointer is not null and the requested interface is unsupported + //! + //! See @ref page_query for more information. + //! @{ - //! Swap pointers with a WRL ComPtr to the same interface. - void swap(Microsoft::WRL::ComPtr& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other.Detach(); - other.Attach(ptr); - } + //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = + //! m_ptr.try_query();` (null result when interface is unsupported or queried pointer is null). See @ref + //! page_query for more information. + //! + //! Identical to the corresponding @ref try_query method with the exception that it can be used when the pointer + //! is null. When used against a null pointer, the returned pointer will always be null and an error will not be + //! produced. + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the + //! interface was + //! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same + //! error handling policy (exceptions, failfast or error codes) as the pointer being queried. + template WI_NODISCARD inline com_ptr_t try_copy() const + { + return com_ptr_t(m_ptr, details::tag_try_com_copy()); + } - //! Swap pointers with a rvalue reference to a WRL ComPtr to the same interface. - void swap(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT - { - swap(other); - } - //! @} // WRL compatibility + //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the + //! query was successful (returns `false` if the pointer is null). See @ref page_query for more information. + //! + //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the + //! pointer is null. When used against a null pointer, the returned pointer will be null and the return value + //! will be `false`. + //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out + //! parameter; do + //! not specify the type directly to the template. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is + //! non-null). + template _Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U **ptrResult) const + { + if (m_ptr) + { + return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); + } + *ptrResult = nullptr; + return false; + } -public: - // Internal Helpers - /// @cond - template - inline com_ptr_t(_In_ U* ptr, details::tag_com_query) : m_ptr(nullptr) - { - err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); - } + //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);` + //! (returns `false` if the pointer is null) See @ref page_query for more information. + //! + //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the + //! pointer is null. When used against a null pointer, the returned pointer will be null and the return value + //! will be `false`. + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be + //! assigned null + //! on failure or if the source pointer being queried is null. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is + //! non-null). Querying + //! a null pointer will return `false` with a null result. + _Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) const + { + if (m_ptr) + { + return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + //! @} - template - inline com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr) - { - details::query_policy_t::query(ptr, &m_ptr); - } + //! @name WRL compatibility + //! @{ - template - inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) : m_ptr(nullptr) - { - if (ptr) + //! Copy construct from a compatible WRL ComPtr. + template > + com_ptr_t(const Microsoft::WRL::ComPtr &other) WI_NOEXCEPT : com_ptr_t(static_cast(other.Get())) + { + } + + //! Move construct from a compatible WRL ComPtr. + template > + com_ptr_t(Microsoft::WRL::ComPtr &&other) WI_NOEXCEPT : m_ptr(other.Detach()) + { + } + + //! Assign from a compatible WRL ComPtr. + template > + com_ptr_t &operator=(const Microsoft::WRL::ComPtr &other) WI_NOEXCEPT + { + return operator=(static_cast(other.Get())); + } + + //! Move assign from a compatible WRL ComPtr. + template > + com_ptr_t &operator=(Microsoft::WRL::ComPtr &&other) WI_NOEXCEPT + { + attach(other.Detach()); + return *this; + } + + //! Swap pointers with a WRL ComPtr to the same interface. + void swap(Microsoft::WRL::ComPtr &other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other.Detach(); + other.Attach(ptr); + } + + //! Swap pointers with a rvalue reference to a WRL ComPtr to the same interface. + void swap(Microsoft::WRL::ComPtr &&other) WI_NOEXCEPT + { + swap(other); + } + //! @} // WRL compatibility + + public: + // Internal Helpers + /// @cond + template inline com_ptr_t(_In_ U *ptr, details::tag_com_query) : m_ptr(nullptr) { err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); } - } - template - inline com_ptr_t(_In_opt_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr) - { - if (ptr) + template inline com_ptr_t(_In_ U *ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr) { details::query_policy_t::query(ptr, &m_ptr); } - } - /// @endcond -private: - pointer m_ptr; -}; + template inline com_ptr_t(_In_opt_ U *ptr, details::tag_com_copy) : m_ptr(nullptr) + { + if (ptr) + { + err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); + } + } -// Error-policy driven forms of com_ptr + template inline com_ptr_t(_In_opt_ U *ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr) + { + if (ptr) + { + details::query_policy_t::query(ptr, &m_ptr); + } + } + /// @endcond + + private: + pointer m_ptr; + }; + + // Error-policy driven forms of com_ptr #ifdef WIL_ENABLE_EXCEPTIONS -//! COM pointer, errors throw exceptions (see @ref com_ptr_t for details) -template -using com_ptr = com_ptr_t; + //! COM pointer, errors throw exceptions (see @ref com_ptr_t for details) + template using com_ptr = com_ptr_t; #endif -//! COM pointer, errors return error codes (see @ref com_ptr_t for details) -template -using com_ptr_nothrow = com_ptr_t; + //! COM pointer, errors return error codes (see @ref com_ptr_t for details) + template using com_ptr_nothrow = com_ptr_t; -//! COM pointer, errors fail-fast (see @ref com_ptr_t for details) -template -using com_ptr_failfast = com_ptr_t; + //! COM pointer, errors fail-fast (see @ref com_ptr_t for details) + template using com_ptr_failfast = com_ptr_t; -// Global operators / swap + // Global operators / swap -//! Swaps the given com pointers that have different error handling. -//! Note that there are also corresponding versions to allow you to swap any wil com_ptr with a WRL ComPtr. -template -inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT -{ - left.swap(right); -} + //! Swaps the given com pointers that have different error handling. + //! Note that there are also corresponding versions to allow you to swap any wil com_ptr with a WRL ComPtr. + template + inline void swap(com_ptr_t &left, com_ptr_t &right) WI_NOEXCEPT + { + left.swap(right); + } -//! Swaps the given com pointers that have the same error handling. -template -inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT -{ - left.swap(right); -} + //! Swaps the given com pointers that have the same error handling. + template inline void swap(com_ptr_t &left, com_ptr_t &right) WI_NOEXCEPT + { + left.swap(right); + } -//! Compare two com pointers. -//! Compares the two raw com pointers for equivalence. Does NOT compare object identity with a QI for IUnknown. -//! -//! Note that documentation for all of the various comparators has not been generated to reduce global function -//! clutter, but ALL standard comparison operators are supported between wil com_ptr objects, nullptr_t, and -//! WRL ComPtr. -template -inline bool operator==(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right.get()); -} + //! Compare two com pointers. + //! Compares the two raw com pointers for equivalence. Does NOT compare object identity with a QI for IUnknown. + //! + //! Note that documentation for all of the various comparators has not been generated to reduce global function + //! clutter, but ALL standard comparison operators are supported between wil com_ptr objects, nullptr_t, and + //! WRL ComPtr. + template + inline bool operator==(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right.get()); + } -// We don't document all of the global comparison operators (reduce clutter) -/// @cond -template -inline bool operator<(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right.get()); -} + // We don't document all of the global comparison operators (reduce clutter) + /// @cond + template + inline bool operator<(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right.get()); + } -template -inline bool operator==(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - return (left.get() == nullptr); -} + template + inline bool operator==(const com_ptr_t &left, wistd::nullptr_t) WI_NOEXCEPT + { + return (left.get() == nullptr); + } -template -inline bool operator!=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left == right)); -} + template + inline bool operator!=(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left == right)); + } -template -inline bool operator>=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left < right)); -} + template + inline bool operator>=(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left < right)); + } -template -inline bool operator>(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (right < left); -} + template + inline bool operator>(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + return (right < left); + } -template -inline bool operator<=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(right < left)); -} + template + inline bool operator<=(const com_ptr_t &left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(right < left)); + } -template -inline bool operator==(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT -{ - return (right.get() == nullptr); -} + template + inline bool operator==(wistd::nullptr_t, const com_ptr_t &right) WI_NOEXCEPT + { + return (right.get() == nullptr); + } -template -inline bool operator!=(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - return (!(left == nullptr)); -} + template + inline bool operator!=(const com_ptr_t &left, wistd::nullptr_t) WI_NOEXCEPT + { + return (!(left == nullptr)); + } -template -inline bool operator!=(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(right == nullptr)); -} + template + inline bool operator!=(wistd::nullptr_t, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(right == nullptr)); + } -// WRL ComPtr support + // WRL ComPtr support -template -inline void swap(com_ptr_t& left, Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - left.swap(right); -} + template + inline void swap(com_ptr_t &left, Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + left.swap(right); + } -template -inline bool operator==(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right.Get()); -} + template + inline bool operator==(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right.Get()); + } -template -inline bool operator<(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right.Get()); -} + template + inline bool operator<(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right.Get()); + } -template -inline bool operator!=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - return (!(left == right)); -} + template + inline bool operator!=(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + return (!(left == right)); + } -template -inline bool operator>=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - return (!(left < right)); -} + template + inline bool operator>=(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + return (!(left < right)); + } -template -inline bool operator>(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - return (right < left); -} + template + inline bool operator>(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + return (right < left); + } -template -inline bool operator<=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT -{ - return (!(right < left)); -} + template + inline bool operator<=(const com_ptr_t &left, + const Microsoft::WRL::ComPtr &right) WI_NOEXCEPT + { + return (!(right < left)); + } -template -inline void swap(Microsoft::WRL::ComPtr& left, com_ptr_t& right) WI_NOEXCEPT -{ - right.swap(left); -} + template + inline void swap(Microsoft::WRL::ComPtr &left, com_ptr_t &right) WI_NOEXCEPT + { + right.swap(left); + } -template -inline bool operator==(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.Get() == right.get()); -} + template + inline bool operator==(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.Get() == right.get()); + } -template -inline bool operator<(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.Get() < right.get()); -} + template + inline bool operator<(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.Get() < right.get()); + } -template -inline bool operator!=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left == right)); -} + template + inline bool operator!=(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left == right)); + } -template -inline bool operator>=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left < right)); -} + template + inline bool operator>=(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left < right)); + } -template -inline bool operator>(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (right < left); -} + template + inline bool operator>(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + return (right < left); + } -template -inline bool operator<=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(right < left)); -} + template + inline bool operator<=(const Microsoft::WRL::ComPtr &left, + const com_ptr_t &right) WI_NOEXCEPT + { + return (!(right < left)); + } -// raw COM pointer support -// -// Use these for convenience and to avoid unnecessary AddRef/Release cyles when using raw -// pointers to access STL containers. Specify std::less<> to benefit from operator<. -// -// Example: std::set, std::less<>> set; + // raw COM pointer support + // + // Use these for convenience and to avoid unnecessary AddRef/Release cyles when using raw + // pointers to access STL containers. Specify std::less<> to benefit from operator<. + // + // Example: std::set, std::less<>> set; -template -inline bool operator==(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right); -} + template + inline bool operator==(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right); + } -template -inline bool operator<(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right); -} + template + inline bool operator<(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right); + } -template -inline bool operator!=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - return (!(left == right)); -} + template + inline bool operator!=(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + return (!(left == right)); + } -template -inline bool operator>=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - return (!(left < right)); -} + template + inline bool operator>=(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + return (!(left < right)); + } -template -inline bool operator>(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - return (right < left); -} + template + inline bool operator>(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + return (right < left); + } -template -inline bool operator<=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT -{ - return (!(right < left)); -} + template + inline bool operator<=(const com_ptr_t &left, TRight *right) WI_NOEXCEPT + { + return (!(right < left)); + } -template -inline bool operator==(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left == right.get()); -} + template + inline bool operator==(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left == right.get()); + } -template -inline bool operator<(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - static_assert( - __is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), - "comparison operator requires left and right pointers to be compatible"); - return (left < right.get()); -} + template + inline bool operator<(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft *, TRight *) || __is_convertible_to(TRight *, TLeft *), + "comparison operator requires left and right pointers to be compatible"); + return (left < right.get()); + } -template -inline bool operator!=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left == right)); -} + template + inline bool operator!=(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left == right)); + } -template -inline bool operator>=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(left < right)); -} + template + inline bool operator>=(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(left < right)); + } -template -inline bool operator>(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (right < left); -} + template + inline bool operator>(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + return (right < left); + } -template -inline bool operator<=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT -{ - return (!(right < left)); -} + template + inline bool operator<=(TLeft *left, const com_ptr_t &right) WI_NOEXCEPT + { + return (!(right < left)); + } -// suppress documentation of every single comparison operator -/// @endcond + // suppress documentation of every single comparison operator + /// @endcond -//! An overloaded function that retrieves the raw com pointer from a raw pointer, wil::com_ptr_t, WRL ComPtr, or -//! Platform::Object^. This function is primarily useful by library or helper code. It allows code to be written to accept a -//! forwarding reference template that can be used as an input com pointer. That input com pointer is allowed to be any of: -//! * Raw Pointer: `T* com_raw_ptr(T* ptr)` -//! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t& ptr)` -//! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr)` -//! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)` -//! -//! Which in turn allows code like the following to be written: -//! ~~~~ -//! template -//! void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) -//! { -//! auto raw = com_raw_ptr(wistd::forward(ptrSource)); -//! // decltype(raw) has the type of the inner pointer and raw is guaranteed to be a raw com pointer -//! ~~~~ -template -T* com_raw_ptr(T* ptr) -{ - return ptr; -} + //! An overloaded function that retrieves the raw com pointer from a raw pointer, wil::com_ptr_t, WRL ComPtr, + //! or Platform::Object^. This function is primarily useful by library or helper code. It allows code to be + //! written to accept a forwarding reference template that can be used as an input com pointer. That input com + //! pointer is allowed to be any of: + //! * Raw Pointer: `T* com_raw_ptr(T* ptr)` + //! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t& ptr)` + //! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr)` + //! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)` + //! + //! Which in turn allows code like the following to be written: + //! ~~~~ + //! template + //! void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) + //! { + //! auto raw = com_raw_ptr(wistd::forward(ptrSource)); + //! // decltype(raw) has the type of the inner pointer and raw is guaranteed to be a raw com pointer + //! ~~~~ + template T *com_raw_ptr(T *ptr) + { + return ptr; + } -/// @cond -template -T* com_raw_ptr(const wil::com_ptr_t& ptr) -{ - return ptr.get(); -} + /// @cond + template T *com_raw_ptr(const wil::com_ptr_t &ptr) + { + return ptr.get(); + } -template -T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr) -{ - return ptr.Get(); -} + template T *com_raw_ptr(const Microsoft::WRL::ComPtr &ptr) + { + return ptr.Get(); + } -// clang-format off + // clang-format off #ifdef __cplusplus_winrt template @@ -1264,499 +1279,517 @@ inline IInspectable* com_raw_ptr(T^ ptr) } #endif -// clang-format on -/// @endcond + // clang-format on + /// @endcond #ifdef WIL_ENABLE_EXCEPTIONS -//! Constructs a `com_ptr` from a raw pointer. -//! This avoids having to restate the interface in pre-C++20. -//! Starting in C++20, you can write `wil::com_ptr(p)` directly. -//! ~~~ -//! void example(ILongNamedThing* thing) -//! { -//! callback([thing = wil::make_com_ptr(thing)] { /* do something */ }); -//! } -//! ~~~ -template -com_ptr make_com_ptr(T* p) -{ - return p; -} -#endif - -//! Constructs a `com_ptr_nothrow` from a raw pointer. -//! This avoids having to restate the interface in pre-C++20. -//! Starting in C++20, you can write `wil::com_ptr_nothrow(p)` directly. -//! ~~~ -//! void example(ILongNamedThing* thing) -//! { -//! callback([thing = wil::make_com_ptr_nothrow(thing)] { /* do something */ }); -//! } -//! ~~~ -template -com_ptr_nothrow make_com_ptr_nothrow(T* p) -{ - return p; -} - -//! Constructs a `com_ptr_failfast` from a raw pointer. -//! This avoids having to restate the interface in pre-C++20. -//! Starting in C++20, you can write `wil::com_ptr_failfast(p)` directly. -//! ~~~ -//! void example(ILongNamedThing* thing) -//! { -//! callback([thing = wil::make_com_ptr_failfast(thing)] { /* do something */ }); -//! } -//! ~~~ -template -com_ptr_failfast make_com_ptr_failfast(T* p) -{ - return p; -} - -//! @name Stand-alone query helpers -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * Retrieves the requested interface -//! * AV if the source pointer is null -//! * Produce an error if the requested interface is unsupported -//! -//! See @ref page_query for more information -//! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. -template -inline com_ptr com_query(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_com_query()); -} -#endif - -//! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if -//! unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. -template -inline com_ptr_failfast com_query_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_com_query()); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. -template -_Success_true_ void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - __analysis_assume(*ptrResult != nullptr); -} -#endif - -//! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. -template -_Success_true_ void com_query_to_failfast(T&& ptrSource, _COM_Outptr_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - __analysis_assume(*ptrResult != nullptr); -} - -//! Queries for the interface specified by the type of the output parameter (returns an error if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. -//! @return Returns an HRESULT representing whether the query succeeded. -template -HRESULT com_query_to_nothrow(T&& ptrSource, _COM_Outptr_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::query_policy_t::query(raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. -template -_Success_true_ void com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - __analysis_assume(*ptrResult != nullptr); -} -#endif - -//! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. -template -_Success_true_ void com_query_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - __analysis_assume(*ptrResult != nullptr); -} - -//! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. -template -HRESULT com_query_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::query_policy_t::query(raw, riid, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; -} -//! @} - -//! @name Stand-alone try query helpers -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * Attempts to retrieves the requested interface -//! * AV if the source pointer is null -//! * Produce null if the requested interface is unsupported -//! * bool returns 'true' when query was successful (non-null return result) -//! -//! See @ref page_query for more information. -//! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if -//! unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested -//! interface was not supported. -template -inline com_ptr try_com_query(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_try_com_query()); -} -#endif - -//! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if -//! unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the -//! requested interface was not supported. -template -inline com_ptr_failfast try_com_query_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_try_com_query()); -} - -//! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns -//! null if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the -//! requested interface was not supported. -template -inline com_ptr_nothrow try_com_query_nothrow(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_nothrow(raw, details::tag_try_com_query()); -} - -//! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. -//! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be -//! null. -//! @return A bool value representing whether the query was successful (non-null return result). -template -_Success_return_ bool try_com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return (SUCCEEDED(details::query_policy_t::query(raw, ptrResult))); -} - -//! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be -//! null. -//! @return A bool value representing whether the query was successful (non-null return result). -template -_Success_return_ bool try_com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return (SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult))); -} -//! @} - -//! @name Stand-alone copy helpers -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * Retrieves the requested interface -//! * Succeeds with null if the source pointer is null -//! * Produce an error if the requested interface is unsupported -//! -//! See @ref page_query for more information -//! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported, -//! preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the -//! source is null. -template -inline com_ptr com_copy(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_com_copy()); -} -#endif - -//! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if -//! unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the -//! source is null. -template -inline com_ptr_failfast com_copy_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_com_copy()); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. -template -_Success_true_ void com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Constructs a `com_ptr` from a raw pointer. + //! This avoids having to restate the interface in pre-C++20. + //! Starting in C++20, you can write `wil::com_ptr(p)` directly. + //! ~~~ + //! void example(ILongNamedThing* thing) + //! { + //! callback([thing = wil::make_com_ptr(thing)] { /* do something */ }); + //! } + //! ~~~ + template com_ptr make_com_ptr(T *p) { + return p; + } +#endif + + //! Constructs a `com_ptr_nothrow` from a raw pointer. + //! This avoids having to restate the interface in pre-C++20. + //! Starting in C++20, you can write `wil::com_ptr_nothrow(p)` directly. + //! ~~~ + //! void example(ILongNamedThing* thing) + //! { + //! callback([thing = wil::make_com_ptr_nothrow(thing)] { /* do something */ }); + //! } + //! ~~~ + template com_ptr_nothrow make_com_ptr_nothrow(T *p) + { + return p; + } + + //! Constructs a `com_ptr_failfast` from a raw pointer. + //! This avoids having to restate the interface in pre-C++20. + //! Starting in C++20, you can write `wil::com_ptr_failfast(p)` directly. + //! ~~~ + //! void example(ILongNamedThing* thing) + //! { + //! callback([thing = wil::make_com_ptr_failfast(thing)] { /* do something */ }); + //! } + //! ~~~ + template com_ptr_failfast make_com_ptr_failfast(T *p) + { + return p; + } + + //! @name Stand-alone query helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Retrieves the requested interface + //! * AV if the source pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if + //! unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed + //! not null. + template inline com_ptr com_query(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_com_query()); + } +#endif + + //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface + //! (fail-fast if unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed + //! not null. + template inline com_ptr_failfast com_query_failfast(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_com_query()); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template _Success_true_ void com_query_to(T &&ptrSource, _COM_Outptr_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - return; + __analysis_assume(*ptrResult != nullptr); } - *ptrResult = nullptr; -} #endif -//! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. -template -_Success_true_ void com_copy_to_failfast(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to_failfast(T &&ptrSource, _COM_Outptr_ U **ptrResult) { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - return; + __analysis_assume(*ptrResult != nullptr); } - *ptrResult = nullptr; -} -//! Queries for the interface specified by the type of the output parameter (returns an error if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the -//! source is null. -//! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). -template -HRESULT com_copy_to_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. + //! @return Returns an HRESULT representing whether the query succeeded. + template HRESULT com_query_to_nothrow(T &&ptrSource, _COM_Outptr_ U **ptrResult) { - RETURN_HR(details::query_policy_t::query(raw, ptrResult)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::query_policy_t::query(raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + return hr; } - *ptrResult = nullptr; - return S_OK; -} #ifdef WIL_ENABLE_EXCEPTIONS -//! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. -template -_Success_true_ void com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template _Success_true_ void com_query_to(T &&ptrSource, REFIID riid, _COM_Outptr_ void **ptrResult) { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - return; + __analysis_assume(*ptrResult != nullptr); } - *ptrResult = nullptr; -} #endif -//! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. -template -_Success_true_ void com_copy_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to_failfast(T &&ptrSource, REFIID riid, _COM_Outptr_ void **ptrResult) { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - return; + __analysis_assume(*ptrResult != nullptr); } - *ptrResult = nullptr; -} -//! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the -//! source is null. -//! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). -template -HRESULT com_copy_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. + template HRESULT com_query_to_nothrow(T &&ptrSource, REFIID riid, _COM_Outptr_ void **ptrResult) { - RETURN_HR(details::query_policy_t::query(raw, riid, ptrResult)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::query_policy_t::query(raw, riid, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + return hr; } - *ptrResult = nullptr; - return S_OK; -} -//! @} + //! @} -//! @name Stand-alone try copy helpers -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * Attempts to retrieves the requested interface -//! * Succeeds with null if the source pointer is null -//! * Produce null if the requested interface is unsupported -//! * bool returns 'true' when query was successful (non-null return result) -//! -//! See @ref page_query for more information. -//! @{ + //! @name Stand-alone try query helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Attempts to retrieves the requested interface + //! * AV if the source pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful (non-null return result) + //! + //! See @ref page_query for more information. + //! @{ #ifdef WIL_ENABLE_EXCEPTIONS -//! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if -//! unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested -//! interface was not supported. -template -inline com_ptr try_com_copy(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_try_com_copy()); -} + //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface + //! (returns null if unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the + //! requested interface was not supported. + template inline com_ptr try_com_query(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_try_com_query()); + } #endif -//! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if -//! unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the -//! requested interface was not supported. -template -inline com_ptr_failfast try_com_copy_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_try_com_copy()); -} - -//! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns -//! null if unsupported, preserves null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null -//! @tparam U Represents the interface being queried -//! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the -//! requested interface was not supported. -template -inline com_ptr_nothrow try_com_copy_nothrow(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_nothrow(raw, details::tag_try_com_copy()); -} - -//! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves -//! null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. -//! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be -//! null. -//! @return A bool value representing whether the query was successful (non-null return result). -template -_Success_return_ bool try_com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface + //! (returns null if unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is + //! null if the + //! requested interface was not supported. + template inline com_ptr_failfast try_com_query_failfast(T &&ptrSource) { - return SUCCEEDED(details::query_policy_t::query(raw, ptrResult)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_try_com_query()); } - *ptrResult = nullptr; - return false; -} -//! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves -//! null). -//! See @ref page_query for more information. -//! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. -//! @param riid The interface to query for -//! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be -//! null. -//! @return A bool value representing whether the query was successful (non-null return result). -template -_Success_return_ bool try_com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) + //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that + //! interface (returns null if unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is + //! null if the + //! requested interface was not supported. + template inline com_ptr_nothrow try_com_query_nothrow(T &&ptrSource) { - return SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_nothrow(raw, details::tag_try_com_query()); } - *ptrResult = nullptr; - return false; -} -//! @} -// clang-format off + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if + //! unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null. + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned + //! pointer will be + //! null. + //! @return A bool value representing whether the query was successful (non-null return result). + template _Success_return_ bool try_com_query_to(T &&ptrSource, _COM_Outptr_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return (SUCCEEDED(details::query_policy_t::query(raw, ptrResult))); + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if + //! unsupported). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should + //! not be null. + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned + //! pointer will be + //! null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_query_to(T &&ptrSource, REFIID riid, _COM_Outptr_ void **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return (SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult))); + } + //! @} + + //! @name Stand-alone copy helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Retrieves the requested interface + //! * Succeeds with null if the source pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if + //! unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null + //! only if the + //! source is null. + template inline com_ptr com_copy(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_com_copy()); + } +#endif + + //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface + //! (fail-fast if unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null + //! only if the + //! source is null. + template inline com_ptr_failfast com_copy_failfast(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_com_copy()); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported, + //! preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the + //! source is null. + template + _Success_true_ void com_copy_to(T &&ptrSource, _COM_Outptr_result_maybenull_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + return; + } + *ptrResult = nullptr; + } +#endif + + //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported, preserves + //! null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the + //! source is null. + template + _Success_true_ void com_copy_to_failfast(T &&ptrSource, _COM_Outptr_result_maybenull_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + return; + } + *ptrResult = nullptr; + } + + //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported, + //! preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure + //! or if the + //! source is null. + //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is + //! null). + template + HRESULT com_copy_to_nothrow(T &&ptrSource, _COM_Outptr_result_maybenull_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::query_policy_t::query(raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported, preserves + //! null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the + //! source is null. + template + _Success_true_ void com_copy_to(T &&ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + return; + } + *ptrResult = nullptr; + } +#endif + + //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the + //! source is null. + template + _Success_true_ void com_copy_to_failfast(T &&ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + return; + } + *ptrResult = nullptr; + } + + //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported, preserves + //! null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure + //! or if the + //! source is null. + //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is + //! null). + template + HRESULT com_copy_to_nothrow(T &&ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::query_policy_t::query(raw, riid, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + //! @} + + //! @name Stand-alone try copy helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Attempts to retrieves the requested interface + //! * Succeeds with null if the source pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful (non-null return result) + //! + //! See @ref page_query for more information. + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface + //! (returns null if unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the + //! requested + //! interface was not supported. + template inline com_ptr try_com_copy(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_try_com_copy()); + } +#endif + + //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface + //! (returns null if unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is + //! null if the + //! requested interface was not supported. + template inline com_ptr_failfast try_com_copy_failfast(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_try_com_copy()); + } + + //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that + //! interface (returns null if unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is + //! null if the + //! requested interface was not supported. + template inline com_ptr_nothrow try_com_copy_nothrow(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_nothrow(raw, details::tag_try_com_copy()); + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if + //! unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null. + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned + //! pointer will be + //! null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_copy_to(T &&ptrSource, _COM_Outptr_result_maybenull_ U **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + return SUCCEEDED(details::query_policy_t::query(raw, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if + //! unsupported, preserves null). See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be + //! null. + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned + //! pointer will be + //! null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_copy_to(T &&ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + return SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + //! @} + + // clang-format off #ifdef __cplusplus_winrt //! @name Stand-alone helpers to query for CX ref ("hat") types from ABI COM types. //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr @@ -1787,464 +1820,469 @@ inline U^ cx_dynamic_cast(T&& ptrSource) WI_NOEXCEPT } //! @} #endif -// clang-format on + // clang-format on -//***************************************************************************** -// Agile References -//***************************************************************************** + //***************************************************************************** + // Agile References + //***************************************************************************** #if (NTDDI_VERSION >= NTDDI_WINBLUE) #ifdef WIL_ENABLE_EXCEPTIONS -//! Agile reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_agile_query for details) -using com_agile_ref = com_ptr; + //! Agile reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_agile_query for + //! details) + using com_agile_ref = com_ptr; #endif -//! Agile reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_agile_query_nothrow for -//! details) -using com_agile_ref_nothrow = com_ptr_nothrow; -//! Agile reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_agile_query_failfast for details) -using com_agile_ref_failfast = com_ptr_failfast; + //! Agile reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref + //! com_agile_query_nothrow for details) + using com_agile_ref_nothrow = com_ptr_nothrow; + //! Agile reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_agile_query_failfast for + //! details) + using com_agile_ref_failfast = com_ptr_failfast; -//! @name Create agile reference helpers -//! * Attempts to retrieve an agile reference to the requested interface (see -//! [RoGetAgileReference](https://msdn.microsoft.com/en-us/library/dn269839.aspx)) -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * `query` methods AV if the source pointer is null -//! * `copy` methods succeed with null if the source pointer is null -//! * Accept optional [AgileReferenceOptions](https://msdn.microsoft.com/en-us/library/dn269836.aspx) -//! -//! See @ref page_query for more information on resolving an agile ref -//! @{ + //! @name Create agile reference helpers + //! * Attempts to retrieve an agile reference to the requested interface (see + //! [RoGetAgileReference](https://msdn.microsoft.com/en-us/library/dn269839.aspx)) + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * `query` methods AV if the source pointer is null + //! * `copy` methods succeed with null if the source pointer is null + //! * Accept optional [AgileReferenceOptions](https://msdn.microsoft.com/en-us/library/dn269836.aspx) + //! + //! See @ref page_query for more information on resolving an agile ref + //! @{ #ifdef WIL_ENABLE_EXCEPTIONS -//! return a com_agile_ref representing the given source pointer (throws an exception on failure) -template -com_agile_ref com_agile_query(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref agileRef; - THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - return agileRef; -} -#endif - -//! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure) -template -com_agile_ref_failfast com_agile_query_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref_failfast agileRef; - FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - return agileRef; -} - -//! return a com_agile_ref_nothrow representing the given source pointer (returns an HRESULT on failure) -template -HRESULT com_agile_query_nothrow(T&& ptrSource, _COM_Outptr_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! return a com_agile_ref representing the given source pointer (throws an exception on failure, source maybe null) -template -com_agile_ref com_agile_copy(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref agileRef; - if (raw) - { - THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - } - return agileRef; -} -#endif - -//! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) -template -com_agile_ref_failfast com_agile_copy_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref_failfast agileRef; - if (raw) - { - FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - } - return agileRef; -} - -//! return an agile ref (com_agile_ref_XXX or other representation) representing the given source pointer (return error on -//! failure, source maybe null) -template -HRESULT com_agile_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; -} -//! @} -#endif - -//***************************************************************************** -// Weak References -//***************************************************************************** - -namespace details -{ + //! return a com_agile_ref representing the given source pointer (throws an exception on failure) template - HRESULT GetWeakReference(T* ptr, _COM_Outptr_ IWeakReference** weakReference) + com_agile_ref com_agile_query(T &&ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) { - static_assert(!wistd::is_same::value, "Cannot get an IWeakReference to an IWeakReference"); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref agileRef; + THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + return agileRef; + } +#endif - *weakReference = nullptr; - com_ptr_nothrow source; - HRESULT hr = ptr->QueryInterface(IID_PPV_ARGS(&source)); - if (SUCCEEDED(hr)) - { - hr = source->GetWeakReference(weakReference); - } + //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure) + template + com_agile_ref_failfast com_agile_query_failfast(T &&ptrSource, + AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref_failfast agileRef; + FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + return agileRef; + } + + //! return a com_agile_ref_nothrow representing the given source pointer (returns an HRESULT on failure) + template + HRESULT com_agile_query_nothrow(T &&ptrSource, _COM_Outptr_ IAgileReference **ptrResult, + AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); return hr; } -} // namespace details #ifdef WIL_ENABLE_EXCEPTIONS -//! Weak reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_weak_query for details) -using com_weak_ref = com_ptr; -#endif -//! Weak reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_weak_query_nothrow for details) -using com_weak_ref_nothrow = com_ptr_nothrow; -//! Weak reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_weak_query_failfast for details) -using com_weak_ref_failfast = com_ptr_failfast; - -//! @name Create weak reference helpers -//! * Attempts to retrieve a weak reference to the requested interface (see WRL's similar -//! [WeakRef](https://msdn.microsoft.com/en-us/library/br244853.aspx)) -//! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr -//! * `query` methods AV if the source pointer is null -//! * `copy` methods succeed with null if the source pointer is null -//! -//! See @ref page_query for more information on resolving a weak ref -//! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS -//! return a com_weak_ref representing the given source pointer (throws an exception on failure) -template -com_weak_ref com_weak_query(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref weakRef; - THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - return weakRef; -} + //! return a com_agile_ref representing the given source pointer (throws an exception on failure, source maybe null) + template + com_agile_ref com_agile_copy(T &&ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref agileRef; + if (raw) + { + THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + } + return agileRef; + } #endif -//! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure) -template -com_weak_ref_failfast com_weak_query_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref_failfast weakRef; - FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - return weakRef; -} - -//! return a com_weak_ref_nothrow representing the given source pointer (returns an HRESULT on failure) -template -HRESULT com_weak_query_nothrow(T&& ptrSource, _COM_Outptr_ IWeakReference** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::GetWeakReference(raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! return a com_weak_ref representing the given source pointer (throws an exception on failure, source maybe null) -template -com_weak_ref com_weak_copy(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref weakRef; - if (raw) + //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template + com_agile_ref_failfast com_agile_copy_failfast(T &&ptrSource, + AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) { - THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref_failfast agileRef; + if (raw) + { + FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + } + return agileRef; } - return weakRef; -} -#endif -//! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) -template -com_weak_ref_failfast com_weak_copy_failfast(T&& ptrSource) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref_failfast weakRef; - if (raw) + //! return an agile ref (com_agile_ref_XXX or other representation) representing the given source pointer (return + //! error on failure, source maybe null) + template + HRESULT com_agile_copy_nothrow(T &&ptrSource, _COM_Outptr_result_maybenull_ IAgileReference **ptrResult, + AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) { - FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; } - return weakRef; -} - -//! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) -template -HRESULT com_weak_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IWeakReference** ptrResult) -{ - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(details::GetWeakReference(raw, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; -} - //! @} +#endif + + //***************************************************************************** + // Weak References + //***************************************************************************** + + namespace details + { + template HRESULT GetWeakReference(T *ptr, _COM_Outptr_ IWeakReference **weakReference) + { + static_assert(!wistd::is_same::value, + "Cannot get an IWeakReference to an IWeakReference"); + + *weakReference = nullptr; + com_ptr_nothrow source; + HRESULT hr = ptr->QueryInterface(IID_PPV_ARGS(&source)); + if (SUCCEEDED(hr)) + { + hr = source->GetWeakReference(weakReference); + } + return hr; + } + } // namespace details + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Weak reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_weak_query for + //! details) + using com_weak_ref = com_ptr; +#endif + //! Weak reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_weak_query_nothrow + //! for details) + using com_weak_ref_nothrow = com_ptr_nothrow; + //! Weak reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_weak_query_failfast for + //! details) + using com_weak_ref_failfast = com_ptr_failfast; + + //! @name Create weak reference helpers + //! * Attempts to retrieve a weak reference to the requested interface (see WRL's similar + //! [WeakRef](https://msdn.microsoft.com/en-us/library/br244853.aspx)) + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * `query` methods AV if the source pointer is null + //! * `copy` methods succeed with null if the source pointer is null + //! + //! See @ref page_query for more information on resolving a weak ref + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_weak_ref representing the given source pointer (throws an exception on failure) + template com_weak_ref com_weak_query(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref weakRef; + THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + return weakRef; + } +#endif + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure) + template com_weak_ref_failfast com_weak_query_failfast(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref_failfast weakRef; + FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + return weakRef; + } + + //! return a com_weak_ref_nothrow representing the given source pointer (returns an HRESULT on failure) + template HRESULT com_weak_query_nothrow(T &&ptrSource, _COM_Outptr_ IWeakReference **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::GetWeakReference(raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + return hr; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_weak_ref representing the given source pointer (throws an exception on failure, source maybe null) + template com_weak_ref com_weak_copy(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref weakRef; + if (raw) + { + THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + } + return weakRef; + } +#endif + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template com_weak_ref_failfast com_weak_copy_failfast(T &&ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref_failfast weakRef; + if (raw) + { + FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + } + return weakRef; + } + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template + HRESULT com_weak_copy_nothrow(T &&ptrSource, _COM_Outptr_result_maybenull_ IWeakReference **ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::GetWeakReference(raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + + //! @} #pragma region COM Object Helpers -template -inline bool is_agile(T&& ptrSource) -{ - wil::com_ptr_nothrow agileObject; - return SUCCEEDED(com_raw_ptr(wistd::forward(ptrSource))->QueryInterface(IID_PPV_ARGS(&agileObject))); -} + template inline bool is_agile(T &&ptrSource) + { + wil::com_ptr_nothrow agileObject; + return SUCCEEDED(com_raw_ptr(wistd::forward(ptrSource))->QueryInterface(IID_PPV_ARGS(&agileObject))); + } -/** constructs a COM object using an CLSID on a specific interface or IUnknown.*/ -template -wil::com_ptr_t CoCreateInstance(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - wil::com_ptr_t result; - error_policy::HResult(::CoCreateInstance(rclsid, nullptr, dwClsContext, IID_PPV_ARGS(&result))); - return result; -} + /** constructs a COM object using an CLSID on a specific interface or IUnknown.*/ + template + wil::com_ptr_t CoCreateInstance(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + wil::com_ptr_t result; + error_policy::HResult(::CoCreateInstance(rclsid, nullptr, dwClsContext, IID_PPV_ARGS(&result))); + return result; + } -/** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or -IUnknown. */ -template -wil::com_ptr_t CoCreateInstance(DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoCreateInstance(__uuidof(Class), dwClsContext); -} + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface + or IUnknown. */ + template + wil::com_ptr_t CoCreateInstance(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstance(__uuidof(Class), dwClsContext); + } -/** constructs a COM object using an CLSID on a specific interface or IUnknown. */ -template -wil::com_ptr_failfast CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT -{ - return CoCreateInstance(rclsid, dwClsContext); -} + /** constructs a COM object using an CLSID on a specific interface or IUnknown. */ + template + wil::com_ptr_failfast CoCreateInstanceFailFast(REFCLSID rclsid, + DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT + { + return CoCreateInstance(rclsid, dwClsContext); + } -/** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or -IUnknown. */ -template -wil::com_ptr_failfast CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT -{ - return CoCreateInstanceFailFast(__uuidof(Class), dwClsContext); -} + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface + or IUnknown. */ + template + wil::com_ptr_failfast CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT + { + return CoCreateInstanceFailFast(__uuidof(Class), dwClsContext); + } -/** constructs a COM object using an CLSID on a specific interface or IUnknown. -Note, failures are reported as a null result, the HRESULT is lost. */ -template -wil::com_ptr_nothrow CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT -{ - return CoCreateInstance(rclsid, dwClsContext); -} + /** constructs a COM object using an CLSID on a specific interface or IUnknown. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoCreateInstanceNoThrow(REFCLSID rclsid, + DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT + { + return CoCreateInstance(rclsid, dwClsContext); + } -/** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or -IUnknown. Note, failures are reported as a null result, the HRESULT is lost. */ -template -wil::com_ptr_nothrow CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT -{ - return CoCreateInstanceNoThrow(__uuidof(Class), dwClsContext); -} + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface + or IUnknown. Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT + { + return CoCreateInstanceNoThrow(__uuidof(Class), dwClsContext); + } -/** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ -template -wil::com_ptr_t CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - wil::com_ptr_t result; - error_policy::HResult(CoGetClassObject(rclsid, dwClsContext, nullptr, IID_PPV_ARGS(&result))); - return result; -} + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ + template + wil::com_ptr_t CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + wil::com_ptr_t result; + error_policy::HResult(CoGetClassObject(rclsid, dwClsContext, nullptr, IID_PPV_ARGS(&result))); + return result; + } -/** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) -on IClassFactory or a specific interface. */ -template -wil::com_ptr_t CoGetClassObject(DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoGetClassObject(__uuidof(Class), dwClsContext); -} + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. */ + template + wil::com_ptr_t CoGetClassObject(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(__uuidof(Class), dwClsContext); + } -/** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ -template -wil::com_ptr_failfast CoGetClassObjectFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoGetClassObject(rclsid, dwClsContext); -} + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ + template + wil::com_ptr_failfast CoGetClassObjectFailFast(REFCLSID rclsid, + DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(rclsid, dwClsContext); + } -/** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) -on IClassFactory or a specific interface. */ -template -wil::com_ptr_failfast CoGetClassObjectFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoGetClassObjectFailFast(__uuidof(Class), dwClsContext); -} + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. */ + template + wil::com_ptr_failfast CoGetClassObjectFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObjectFailFast(__uuidof(Class), dwClsContext); + } -/** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. -Note, failures are reported as a null result, the HRESULT is lost. */ -template -wil::com_ptr_nothrow CoGetClassObjectNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoGetClassObject(rclsid, dwClsContext); -} + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoGetClassObjectNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(rclsid, dwClsContext); + } -/** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) -on IClassFactory or a specific interface. -Note, failures are reported as a null result, the HRESULT is lost. */ -template -wil::com_ptr_nothrow CoGetClassObjectNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) -{ - return CoGetClassObjectNoThrow(__uuidof(Class), dwClsContext); -} + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoGetClassObjectNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObjectNoThrow(__uuidof(Class), dwClsContext); + } #if __cpp_lib_apply && WIL_USE_STL && WI_HAS_INCLUDE(, 1) -/// @cond -namespace details -{ - template - auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx) noexcept + /// @cond + namespace details { - MULTI_QI multiQis[sizeof...(Results)]{}; - const IID* iids[sizeof...(Results)]{&__uuidof(Results)...}; - - static_assert(sizeof...(Results) > 0); - - for (auto i = 0U; i < sizeof...(Results); ++i) + template + auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx) noexcept { - multiQis[i].pIID = iids[i]; - } + MULTI_QI multiQis[sizeof...(Results)]{}; + const IID *iids[sizeof...(Results)]{&__uuidof(Results)...}; - const auto hr = CoCreateInstanceEx(clsid, nullptr, clsCtx, nullptr, ARRAYSIZE(multiQis), multiQis); + static_assert(sizeof...(Results) > 0); - std::tuple...> resultTuple; + for (auto i = 0U; i < sizeof...(Results); ++i) + { + multiQis[i].pIID = iids[i]; + } - std::apply( - [i = 0, &multiQis](auto&... a) mutable { - (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); - }, - resultTuple); - return std::tuple(hr, std::move(resultTuple)); - } + const auto hr = CoCreateInstanceEx(clsid, nullptr, clsCtx, nullptr, ARRAYSIZE(multiQis), multiQis); - template - auto com_multi_query(IUnknown* obj) - { - MULTI_QI multiQis[sizeof...(Results)]{}; - const IID* iids[sizeof...(Results)]{&__uuidof(Results)...}; + std::tuple...> resultTuple; - static_assert(sizeof...(Results) > 0); - - for (auto i = 0U; i < sizeof...(Results); ++i) - { - multiQis[i].pIID = iids[i]; - } - - std::tuple...> resultTuple{}; - - wil::com_ptr_nothrow multiQi; - auto hr = obj->QueryInterface(IID_PPV_ARGS(&multiQi)); - if (SUCCEEDED(hr)) - { - hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis); std::apply( - [i = 0, &multiQis](auto&... a) mutable { - (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); + [i = 0, &multiQis](auto &...a) mutable { + (a.attach(reinterpret_cast::type::pointer>( + multiQis[i++].pItf)), + ...); }, resultTuple); + return std::tuple(hr, std::move(resultTuple)); } - return std::tuple{hr, std::move(resultTuple)}; - } -} // namespace details -/// @endcond + + template auto com_multi_query(IUnknown *obj) + { + MULTI_QI multiQis[sizeof...(Results)]{}; + const IID *iids[sizeof...(Results)]{&__uuidof(Results)...}; + + static_assert(sizeof...(Results) > 0); + + for (auto i = 0U; i < sizeof...(Results); ++i) + { + multiQis[i].pIID = iids[i]; + } + + std::tuple...> resultTuple{}; + + wil::com_ptr_nothrow multiQi; + auto hr = obj->QueryInterface(IID_PPV_ARGS(&multiQi)); + if (SUCCEEDED(hr)) + { + hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis); + std::apply( + [i = 0, &multiQis](auto &...a) mutable { + (a.attach(reinterpret_cast::type::pointer>( + multiQis[i++].pItf)), + ...); + }, + resultTuple); + } + return std::tuple{hr, std::move(resultTuple)}; + } + } // namespace details + /// @endcond #ifdef WIL_ENABLE_EXCEPTIONS -// CoCreateInstanceEx can be used to improve performance by requesting multiple interfaces -// from an object at create time. This is most useful for out of process (OOP) servers, saving -// and RPC per extra interface requested. -template -auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - THROW_IF_FAILED(error); - THROW_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); - return result; -} + // CoCreateInstanceEx can be used to improve performance by requesting multiple interfaces + // from an object at create time. This is most useful for out of process (OOP) servers, saving + // and RPC per extra interface requested. + template auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) + { + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + THROW_IF_FAILED(error); + THROW_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); + return result; + } -template -auto TryCoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; -} + template auto TryCoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) + { + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + return result; + } #endif -// Returns [error, result] where result is a tuple with each of the requested interfaces. -template -auto CoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - if (SUCCEEDED(error) && (error == CO_S_NOTALLINTERFACES)) + // Returns [error, result] where result is a tuple with each of the requested interfaces. + template + auto CoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept { - return std::tuple{E_NOINTERFACE, {}}; + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + if (SUCCEEDED(error) && (error == CO_S_NOTALLINTERFACES)) + { + return std::tuple{E_NOINTERFACE, {}}; + } + return std::tuple{error, result}; } - return std::tuple{error, result}; -} -template -auto TryCoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; -} + template + auto TryCoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept + { + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + return result; + } -template -auto CoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - FAIL_FAST_IF_FAILED(error); - FAIL_FAST_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); - return result; -} + template + auto CoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept + { + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + FAIL_FAST_IF_FAILED(error); + FAIL_FAST_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); + return result; + } -template -auto TryCoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept -{ - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; -} + template + auto TryCoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept + { + auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -template -auto com_multi_query(IUnknown* obj) -{ - auto [error, result] = details::com_multi_query(obj); - THROW_IF_FAILED(error); - THROW_HR_IF(E_NOINTERFACE, error == S_FALSE); - return result; -} + template auto com_multi_query(IUnknown *obj) + { + auto [error, result] = details::com_multi_query(obj); + THROW_IF_FAILED(error); + THROW_HR_IF(E_NOINTERFACE, error == S_FALSE); + return result; + } -template -auto try_com_multi_query(IUnknown* obj) -{ - auto [error, result] = details::com_multi_query(obj); - return result; -} + template auto try_com_multi_query(IUnknown *obj) + { + auto [error, result] = details::com_multi_query(obj); + return result; + } #endif #endif // __cpp_lib_apply && WI_HAS_INCLUDE(, 1) @@ -2253,1094 +2291,1103 @@ auto try_com_multi_query(IUnknown* obj) #pragma region Stream helpers -/** Read data from a stream into a buffer. -Reads up to a certain number of bytes into a buffer. Returns the amount of data written, which -may be less than the amount requested if the stream ran out. -@code -IStream* source = // ... -ULONG dataBlob = 0; -size_t read = 0; -RETURN_IF_FAILED(wil::stream_read_partial_nothrow(source, &dataBlob, sizeof(dataBlob), &read)); -if (read != sizeof(dataBlob)) -{ - // end of stream, probably -} -else if (dataBlob == 0x8675309) -{ - DoThing(dataBlob); -} -@endcode -@param stream The stream from which to read at most `size` bytes. -@param data A buffer into which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -@param wrote The amount, in bytes, of data read from `stream` into `data` -*/ -inline HRESULT stream_read_partial_nothrow( - _In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, *wrote) void* data, unsigned long size, unsigned long* wrote) -{ - RETURN_HR(stream->Read(data, size, wrote)); -} + /** Read data from a stream into a buffer. + Reads up to a certain number of bytes into a buffer. Returns the amount of data written, which + may be less than the amount requested if the stream ran out. + @code + IStream* source = // ... + ULONG dataBlob = 0; + size_t read = 0; + RETURN_IF_FAILED(wil::stream_read_partial_nothrow(source, &dataBlob, sizeof(dataBlob), &read)); + if (read != sizeof(dataBlob)) + { + // end of stream, probably + } + else if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + @endcode + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @param wrote The amount, in bytes, of data read from `stream` into `data` + */ + inline HRESULT stream_read_partial_nothrow(_In_ ISequentialStream *stream, + _Out_writes_bytes_to_(size, *wrote) void *data, unsigned long size, + unsigned long *wrote) + { + RETURN_HR(stream->Read(data, size, wrote)); + } -/** Read an exact number of bytes from a stream into a buffer. -Fails if the stream didn't read all the bytes requested. -~~~~ -IStream* source = // ... -ULONG dataBlob = 0; -RETURN_IF_FAILED(wil::stream_read_nothrow(source, &dataBlob, sizeof(dataBlob))); -if (dataBlob == 0x8675309) -{ - DoThing(dataBlob); -} -~~~~ -@param stream The stream from which to read at most `size` bytes. -@param data A buffer into which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -@return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream - did not read the complete buffer. -*/ -inline HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) -{ - unsigned long didRead; - RETURN_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), didRead != size); + /** Read an exact number of bytes from a stream into a buffer. + Fails if the stream didn't read all the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + RETURN_IF_FAILED(wil::stream_read_nothrow(source, &dataBlob, sizeof(dataBlob))); + if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream + did not read the complete buffer. + */ + inline HRESULT stream_read_nothrow(_In_ ISequentialStream *stream, _Out_writes_bytes_all_(size) void *data, + unsigned long size) + { + unsigned long didRead; + RETURN_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), didRead != size); - return S_OK; -} + return S_OK; + } -/** Read from a stream into a POD type. -Fails if the stream didn't have enough bytes. -~~~~ -IStream* source = // ... -MY_HEADER header{}; -RETURN_IF_FAILED(wil::stream_read_nothrow(source, &header)); -if (header.Version == 0x8675309) -{ - ConsumeOldHeader(stream, header); -} -~~~~ -@param stream The stream from which to read at most `size` bytes. -@param pThing The POD data type to read from the stream. -@return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream - did not read the complete buffer. -*/ -template -HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_ T* pThing) -{ - static_assert(__is_pod(T), "Type must be POD."); - return stream_read_nothrow(stream, pThing, sizeof(T)); -} + /** Read from a stream into a POD type. + Fails if the stream didn't have enough bytes. + ~~~~ + IStream* source = // ... + MY_HEADER header{}; + RETURN_IF_FAILED(wil::stream_read_nothrow(source, &header)); + if (header.Version == 0x8675309) + { + ConsumeOldHeader(stream, header); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param pThing The POD data type to read from the stream. + @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream + did not read the complete buffer. + */ + template HRESULT stream_read_nothrow(_In_ ISequentialStream *stream, _Out_ T *pThing) + { + static_assert(__is_pod(T), "Type must be POD."); + return stream_read_nothrow(stream, pThing, sizeof(T)); + } -/** Write an exact number of bytes to a stream from a buffer. -Fails if the stream didn't read write the bytes requested. -~~~~ -IStream* source = // ... -ULONG dataBlob = 0x8675309; -RETURN_IF_FAILED(wil::stream_write_nothrow(source, &dataBlob, sizeof(dataBlob))); -~~~~ -@param stream The stream to which to write at most `size` bytes. -@param data A buffer from which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -*/ -inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) -{ - unsigned long wrote; - RETURN_IF_FAILED(stream->Write(data, size, &wrote)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), wrote != size); + /** Write an exact number of bytes to a stream from a buffer. + Fails if the stream didn't read write the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0x8675309; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, &dataBlob, sizeof(dataBlob))); + ~~~~ + @param stream The stream to which to write at most `size` bytes. + @param data A buffer from which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline HRESULT stream_write_nothrow(_In_ ISequentialStream *stream, _In_reads_bytes_(size) const void *data, + unsigned long size) + { + unsigned long wrote; + RETURN_IF_FAILED(stream->Write(data, size, &wrote)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), wrote != size); - return S_OK; -} + return S_OK; + } -/** Write a POD type to a stream. -Fails if not all the bytes were written. -~~~~ -IStream* source = // ... -MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; -RETURN_IF_FAILED(wil::stream_write_nothrow(source, header)); + /** Write a POD type to a stream. + Fails if not all the bytes were written. + ~~~~ + IStream* source = // ... + MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, header)); -ULONGLONG value = 16; -RETURN_IF_FAILED(wil::stream_write_nothrow(source, value)); -~~~~ -@param stream The stream to which to write `thing` -@param thing The POD data type to write to the stream. -*/ -template -inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, const T& thing) -{ - return stream_write_nothrow(stream, wistd::addressof(thing), sizeof(thing)); -} + ULONGLONG value = 16; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, value)); + ~~~~ + @param stream The stream to which to write `thing` + @param thing The POD data type to write to the stream. + */ + template inline HRESULT stream_write_nothrow(_In_ ISequentialStream *stream, const T &thing) + { + return stream_write_nothrow(stream, wistd::addressof(thing), sizeof(thing)); + } -/** Retrieve the size of this stream, in bytes -~~~~ -IStream* source = // ... -ULONGLONG size; -RETURN_IF_FAILED(wil::stream_size_nothrow(source, &size)); -RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX); -~~~~ -@param stream The stream whose size is to be returned in `value` -@param value The size, in bytes, reported by `stream` -*/ -inline HRESULT stream_size_nothrow(_In_ IStream* stream, _Out_ unsigned long long* value) -{ - STATSTG st{}; - RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME)); - *value = st.cbSize.QuadPart; + /** Retrieve the size of this stream, in bytes + ~~~~ + IStream* source = // ... + ULONGLONG size; + RETURN_IF_FAILED(wil::stream_size_nothrow(source, &size)); + RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param value The size, in bytes, reported by `stream` + */ + inline HRESULT stream_size_nothrow(_In_ IStream *stream, _Out_ unsigned long long *value) + { + STATSTG st{}; + RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME)); + *value = st.cbSize.QuadPart; - return S_OK; -} + return S_OK; + } -/** Seek a stream to a relative offset or absolute position -~~~~ -IStream* source = // ... -unsigned long long landed; -RETURN_IF_FAILED(wil::stream_seek_nothrow(source, 16, STREAM_SEEK_CUR, &landed)); -RETURN_IF_FAILED(wil::stream_seek_nothrow(source, -5, STREAM_SEEK_END)); -RETURN_IF_FAILED(wil::stream_seek_nothrow(source, LLONG_MAX, STREAM_SEEK_CUR)); -~~~~ -@param stream The stream to seek -@param offset The position, in bytes from the current position, to seek -@param from The starting point from which to seek, from the STREAM_SEEK_* set of values -@param value Optionally receives the new absolute position from the stream -*/ -inline HRESULT stream_seek_nothrow(_In_ IStream* stream, long long offset, unsigned long from, _Out_opt_ unsigned long long* value = nullptr) -{ - LARGE_INTEGER amount{}; - ULARGE_INTEGER landed{}; - amount.QuadPart = offset; - RETURN_IF_FAILED(stream->Seek(amount, from, value ? &landed : nullptr)); - assign_to_opt_param(value, landed.QuadPart); + /** Seek a stream to a relative offset or absolute position + ~~~~ + IStream* source = // ... + unsigned long long landed; + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, 16, STREAM_SEEK_CUR, &landed)); + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, -5, STREAM_SEEK_END)); + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, LLONG_MAX, STREAM_SEEK_CUR)); + ~~~~ + @param stream The stream to seek + @param offset The position, in bytes from the current position, to seek + @param from The starting point from which to seek, from the STREAM_SEEK_* set of values + @param value Optionally receives the new absolute position from the stream + */ + inline HRESULT stream_seek_nothrow(_In_ IStream *stream, long long offset, unsigned long from, + _Out_opt_ unsigned long long *value = nullptr) + { + LARGE_INTEGER amount{}; + ULARGE_INTEGER landed{}; + amount.QuadPart = offset; + RETURN_IF_FAILED(stream->Seek(amount, from, value ? &landed : nullptr)); + assign_to_opt_param(value, landed.QuadPart); - return S_OK; -} + return S_OK; + } -/** Seek a stream to an absolute offset -~~~~ -IStream* source = // ... -RETURN_HR(wil::stream_set_position_nothrow(source, 16)); -~~~~ -@param stream The stream whose size is to be returned in `value` -@param offset The position, in bytes from the start of the stream, to seek to -@param value Optionally receives the new absolute position from the stream -*/ -inline HRESULT stream_set_position_nothrow(_In_ IStream* stream, unsigned long long offset, _Out_opt_ unsigned long long* value = nullptr) -{ - // IStream::Seek(..., _SET) interprets the first parameter as an unsigned value. - return stream_seek_nothrow(stream, static_cast(offset), STREAM_SEEK_SET, value); -} + /** Seek a stream to an absolute offset + ~~~~ + IStream* source = // ... + RETURN_HR(wil::stream_set_position_nothrow(source, 16)); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param offset The position, in bytes from the start of the stream, to seek to + @param value Optionally receives the new absolute position from the stream + */ + inline HRESULT stream_set_position_nothrow(_In_ IStream *stream, unsigned long long offset, + _Out_opt_ unsigned long long *value = nullptr) + { + // IStream::Seek(..., _SET) interprets the first parameter as an unsigned value. + return stream_seek_nothrow(stream, static_cast(offset), STREAM_SEEK_SET, value); + } -/** Seek a relative amount in a stream -~~~~ -IStream* source = // ... -RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, -16)); + /** Seek a relative amount in a stream + ~~~~ + IStream* source = // ... + RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, -16)); -ULONGLONG newPosition; -RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, 16, &newPosition)); -~~~~ -@param stream The stream whose location is to be moved -@param amount The offset, in bytes, to seek the stream. -@param value Set to the new absolute steam position, in bytes -*/ -inline HRESULT stream_seek_from_current_position_nothrow(_In_ IStream* stream, long long amount, _Out_opt_ unsigned long long* value = nullptr) -{ - return stream_seek_nothrow(stream, amount, STREAM_SEEK_CUR, value); -} + ULONGLONG newPosition; + RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, 16, &newPosition)); + ~~~~ + @param stream The stream whose location is to be moved + @param amount The offset, in bytes, to seek the stream. + @param value Set to the new absolute steam position, in bytes + */ + inline HRESULT stream_seek_from_current_position_nothrow(_In_ IStream *stream, long long amount, + _Out_opt_ unsigned long long *value = nullptr) + { + return stream_seek_nothrow(stream, amount, STREAM_SEEK_CUR, value); + } -/** Determine the current byte position in the stream -~~~~ -IStream* source = // ... -ULONGLONG currentPos; -RETURN_IF_FAILED(wil::stream_get_position_nothrow(source, ¤tPos)); -~~~~ -@param stream The stream whose location is to be moved -@param position Set to the current absolute steam position, in bytes -*/ -inline HRESULT stream_get_position_nothrow(_In_ IStream* stream, _Out_ unsigned long long* position) -{ - return stream_seek_from_current_position_nothrow(stream, 0, position); -} + /** Determine the current byte position in the stream + ~~~~ + IStream* source = // ... + ULONGLONG currentPos; + RETURN_IF_FAILED(wil::stream_get_position_nothrow(source, ¤tPos)); + ~~~~ + @param stream The stream whose location is to be moved + @param position Set to the current absolute steam position, in bytes + */ + inline HRESULT stream_get_position_nothrow(_In_ IStream *stream, _Out_ unsigned long long *position) + { + return stream_seek_from_current_position_nothrow(stream, 0, position); + } -/** Moves the stream to absolute position 0 -~~~~ -IStream* source = // ... -RETURN_IF_FAILED(wil::stream_reset_nothrow(source)); -~~~~ -@param stream The stream whose location is to be moved -*/ -inline HRESULT stream_reset_nothrow(_In_ IStream* stream) -{ - return stream_set_position_nothrow(stream, 0); -} + /** Moves the stream to absolute position 0 + ~~~~ + IStream* source = // ... + RETURN_IF_FAILED(wil::stream_reset_nothrow(source)); + ~~~~ + @param stream The stream whose location is to be moved + */ + inline HRESULT stream_reset_nothrow(_In_ IStream *stream) + { + return stream_set_position_nothrow(stream, 0); + } -/** Copy data from one stream to another, returning the final amount copied. -~~~~ -IStream* source = // ... -IStream* target = // ... -ULONGLONG copied; -RETURN_IF_FAILED(wil::stream_copy_bytes_nothrow(source, target, sizeof(MyType), &copied)); -if (copied < sizeof(MyType)) -{ - DoSomethingAboutPartialCopy(); -} -~~~~ -@param source The stream from which to copy at most `amount` bytes -@param target The steam to which to copy at most `amount` bytes -@param amount The maximum number of bytes to copy from `source` to `target` -@param pCopied If non-null, set to the number of bytes copied between the two. -*/ -inline HRESULT stream_copy_bytes_nothrow( - _In_ IStream* source, _In_ IStream* target, unsigned long long amount, _Out_opt_ unsigned long long* pCopied = nullptr) -{ - ULARGE_INTEGER toCopy{}; - ULARGE_INTEGER copied{}; - toCopy.QuadPart = amount; - RETURN_IF_FAILED(source->CopyTo(target, toCopy, nullptr, &copied)); - assign_to_opt_param(pCopied, copied.QuadPart); + /** Copy data from one stream to another, returning the final amount copied. + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied; + RETURN_IF_FAILED(wil::stream_copy_bytes_nothrow(source, target, sizeof(MyType), &copied)); + if (copied < sizeof(MyType)) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The maximum number of bytes to copy from `source` to `target` + @param pCopied If non-null, set to the number of bytes copied between the two. + */ + inline HRESULT stream_copy_bytes_nothrow(_In_ IStream *source, _In_ IStream *target, unsigned long long amount, + _Out_opt_ unsigned long long *pCopied = nullptr) + { + ULARGE_INTEGER toCopy{}; + ULARGE_INTEGER copied{}; + toCopy.QuadPart = amount; + RETURN_IF_FAILED(source->CopyTo(target, toCopy, nullptr, &copied)); + assign_to_opt_param(pCopied, copied.QuadPart); - return S_OK; -} + return S_OK; + } -/** Copy all data from one stream to another, returning the final amount copied. -~~~~ -IStream* source = // ... -IStream* target = // ... -ULONGLONG copied; -RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, &copied)); -if (copied < 8) -{ - DoSomethingAboutPartialCopy(); -} -~~~~ -@param source The stream from which to copy all content -@param target The steam to which to copy all content -@param pCopied If non-null, set to the number of bytes copied between the two. -*/ -inline HRESULT stream_copy_all_nothrow(_In_ IStream* source, _In_ IStream* target, _Out_opt_ unsigned long long* pCopied = nullptr) -{ - return stream_copy_bytes_nothrow(source, target, ULLONG_MAX, pCopied); -} + /** Copy all data from one stream to another, returning the final amount copied. + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied; + RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, &copied)); + if (copied < 8) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy all content + @param target The steam to which to copy all content + @param pCopied If non-null, set to the number of bytes copied between the two. + */ + inline HRESULT stream_copy_all_nothrow(_In_ IStream *source, _In_ IStream *target, + _Out_opt_ unsigned long long *pCopied = nullptr) + { + return stream_copy_bytes_nothrow(source, target, ULLONG_MAX, pCopied); + } -/** Copies an exact amount of data from one stream to another, failing otherwise -~~~~ -IStream* source = // ... -IStream* target = // ... -RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, 16)); -~~~~ -@param source The stream from which to copy at most `amount` bytes -@param target The steam to which to copy at most `amount` bytes -@param amount The number of bytes to copy from `source` to `target` -*/ -inline HRESULT stream_copy_exact_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) -{ - unsigned long long copied; - RETURN_IF_FAILED(stream_copy_bytes_nothrow(source, target, ULLONG_MAX, &copied)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), copied != amount); + /** Copies an exact amount of data from one stream to another, failing otherwise + ~~~~ + IStream* source = // ... + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, 16)); + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The number of bytes to copy from `source` to `target` + */ + inline HRESULT stream_copy_exact_nothrow(_In_ IStream *source, _In_ IStream *target, unsigned long long amount) + { + unsigned long long copied; + RETURN_IF_FAILED(stream_copy_bytes_nothrow(source, target, ULLONG_MAX, &copied)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), copied != amount); - return S_OK; -} + return S_OK; + } -//! Controls behavior when reading a zero-length string from a stream -enum class empty_string_options -{ - //! Zero-length strings are returned as nullptr - returns_null, + //! Controls behavior when reading a zero-length string from a stream + enum class empty_string_options + { + //! Zero-length strings are returned as nullptr + returns_null, - //! Zero-length strings are allocated and returned with zero characters - returns_empty, -}; + //! Zero-length strings are allocated and returned with zero characters + returns_empty, + }; #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) -/** Read a string from a stream and returns an allocated copy -Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format -is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. -Returns a zero-length (but non-null) string if the stream contained a zero-length string. -@code -IStream* source = // ... -wil::unique_cotaskmem_string content; -RETURN_IF_FAILED(wil::stream_read_string_nothrow(source, &content)); -if (wcscmp(content.get(), L"waffles") == 0) -{ - // Waffles! -} -@endcode -@param source The stream from which to read a string -@param value Set to point to the allocated result of reading a string from `source` -@param options Controls behavior when reading a zero-length string from a stream -*/ -inline HRESULT stream_read_string_nothrow( - _In_ ISequentialStream* source, - _When_(options == empty_string_options::returns_empty, _Outptr_result_z_) - _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value, - empty_string_options options = empty_string_options::returns_empty) -{ - unsigned short cch; - RETURN_IF_FAILED(stream_read_nothrow(source, &cch)); - - if ((cch == 0) && (options == empty_string_options::returns_null)) + /** Read a string from a stream and returns an allocated copy + Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format + is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. + Returns a zero-length (but non-null) string if the stream contained a zero-length string. + @code + IStream* source = // ... + wil::unique_cotaskmem_string content; + RETURN_IF_FAILED(wil::stream_read_string_nothrow(source, &content)); + if (wcscmp(content.get(), L"waffles") == 0) { - *value = nullptr; + // Waffles! } - else + @endcode + @param source The stream from which to read a string + @param value Set to point to the allocated result of reading a string from `source` + @param options Controls behavior when reading a zero-length string from a stream + */ + inline HRESULT stream_read_string_nothrow(_In_ ISequentialStream *source, + _When_(options == empty_string_options::returns_empty, _Outptr_result_z_) + _When_(options == empty_string_options::returns_null, + _Outptr_result_maybenull_z_) wchar_t **value, + empty_string_options options = empty_string_options::returns_empty) { - auto allocated = make_unique_cotaskmem_nothrow(static_cast(cch) + 1); - RETURN_IF_NULL_ALLOC(allocated); - RETURN_IF_FAILED(stream_read_nothrow(source, allocated.get(), static_cast(cch) * sizeof(wchar_t))); - allocated[cch] = 0; + unsigned short cch; + RETURN_IF_FAILED(stream_read_nothrow(source, &cch)); - *value = allocated.release(); + if ((cch == 0) && (options == empty_string_options::returns_null)) + { + *value = nullptr; + } + else + { + auto allocated = make_unique_cotaskmem_nothrow(static_cast(cch) + 1); + RETURN_IF_NULL_ALLOC(allocated); + RETURN_IF_FAILED( + stream_read_nothrow(source, allocated.get(), static_cast(cch) * sizeof(wchar_t))); + allocated[cch] = 0; + + *value = allocated.release(); + } + + return S_OK; } - return S_OK; -} - #endif // __WIL_OBJBASE_H -/** Write a string to a stream -Serializes a string into a stream by putting its length and then the wchar_ts in the string -into the stream. Zero-length strings have their length but no data written. This is the -form expected by IStream_ReadStr and wil::string_read_stream. -@code -IStream* target = // ... -RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles", 3)); -// Produces wchar_t[] { 0x3, L'W', L'a', L'f' }; -@endcode -@param target The stream to which to write a string -@param source The string to write. Can be null if `writeLength` is zero -@param writeLength The number of characters to write from source into `target` -*/ -inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_reads_opt_(writeLength) const wchar_t* source, _In_ size_t writeLength) -{ - FAIL_FAST_IF(writeLength > USHRT_MAX); - - RETURN_IF_FAILED(stream_write_nothrow(target, static_cast(writeLength))); - - if (writeLength > 0) + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + @code + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles", 3)); + // Produces wchar_t[] { 0x3, L'W', L'a', L'f' }; + @endcode + @param target The stream to which to write a string + @param source The string to write. Can be null if `writeLength` is zero + @param writeLength The number of characters to write from source into `target` + */ + inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream *target, + _In_reads_opt_(writeLength) const wchar_t *source, + _In_ size_t writeLength) { - RETURN_IF_FAILED(stream_write_nothrow(target, source, static_cast(writeLength) * sizeof(wchar_t))); + FAIL_FAST_IF(writeLength > USHRT_MAX); + + RETURN_IF_FAILED(stream_write_nothrow(target, static_cast(writeLength))); + + if (writeLength > 0) + { + RETURN_IF_FAILED( + stream_write_nothrow(target, source, static_cast(writeLength) * sizeof(wchar_t))); + } + + return S_OK; } - return S_OK; -} - -/** Write a string to a stream -Serializes a string into a stream by putting its length and then the wchar_ts in the string -into the stream. Zero-length strings have their length but no data written. This is the -form expected by IStream_ReadStr and wil::string_read_stream. -@code -IStream* target = // ... -RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles")); -// Produces wchar_t[] { 0x3, L'W', L'a', L'f', L'f', L'l', L'e', L's' }; -@endcode -@param target The stream to which to write a string -@param source The string to write. When nullptr, a zero-length string is written. -*/ -inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) -{ - return stream_write_string_nothrow(target, source, source ? wcslen(source) : 0); -} + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + @code + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles")); + // Produces wchar_t[] { 0x3, L'W', L'a', L'f', L'f', L'l', L'e', L's' }; + @endcode + @param target The stream to which to write a string + @param source The string to write. When nullptr, a zero-length string is written. + */ + inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream *target, _In_opt_z_ const wchar_t *source) + { + return stream_write_string_nothrow(target, source, source ? wcslen(source) : 0); + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Read data from a stream into a buffer. -@code -IStream* source = // ... -ULONG dataBlob = 0; -auto read = wil::stream_read_partial(source, &dataBlob, sizeof(dataBlob)); -if (read != sizeof(dataBlob)) -{ - // end of stream, probably -} -else if (dataBlob == 0x8675309) -{ - DoThing(dataBlob); -} -@endcode -@param stream The stream from which to read at most `size` bytes. -@param data A buffer into which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -@return The amount, in bytes, of data read from `stream` into `data` -*/ -inline unsigned long stream_read_partial(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, return) void* data, unsigned long size) -{ - unsigned long didRead; - THROW_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); + /** Read data from a stream into a buffer. + @code + IStream* source = // ... + ULONG dataBlob = 0; + auto read = wil::stream_read_partial(source, &dataBlob, sizeof(dataBlob)); + if (read != sizeof(dataBlob)) + { + // end of stream, probably + } + else if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + @endcode + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @return The amount, in bytes, of data read from `stream` into `data` + */ + inline unsigned long stream_read_partial(_In_ ISequentialStream *stream, + _Out_writes_bytes_to_(size, return) void *data, unsigned long size) + { + unsigned long didRead; + THROW_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); - return didRead; -} + return didRead; + } -/** Read an exact number of bytes from a stream into a buffer. -Fails if the stream didn't read all the bytes requested by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). -~~~~ -IStream* source = // ... -ULONG dataBlob = 0; -wil::stream_read(source, &dataBlob, sizeof(dataBlob)); -if (dataBlob == 0x8675309) -{ - DoThing(dataBlob); -} -~~~~ -@param stream The stream from which to read at most `size` bytes. -@param data A buffer into which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -*/ -inline void stream_read(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) -{ - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_read_partial(stream, data, size) != size); -} + /** Read an exact number of bytes from a stream into a buffer. + Fails if the stream didn't read all the bytes requested by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + wil::stream_read(source, &dataBlob, sizeof(dataBlob)); + if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline void stream_read(_In_ ISequentialStream *stream, _Out_writes_bytes_all_(size) void *data, unsigned long size) + { + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_read_partial(stream, data, size) != size); + } -/** Read from a stream into a POD type. -Fails if the stream didn't have enough bytes by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). -~~~~ -IStream* source = // ... -MY_HEADER header = wil::stream_read(source); -if (header.Version == 0x8675309) -{ - ConsumeOldHeader(stream, header); -} -~~~~ -@param stream The stream from which to read at most `sizeof(T)` bytes. -@return An instance of `T` read from the stream -*/ -template -T stream_read(_In_ ISequentialStream* stream) -{ - static_assert(__is_pod(T), "Read type must be POD"); - T temp{}; - stream_read(stream, &temp, sizeof(temp)); + /** Read from a stream into a POD type. + Fails if the stream didn't have enough bytes by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). + ~~~~ + IStream* source = // ... + MY_HEADER header = wil::stream_read(source); + if (header.Version == 0x8675309) + { + ConsumeOldHeader(stream, header); + } + ~~~~ + @param stream The stream from which to read at most `sizeof(T)` bytes. + @return An instance of `T` read from the stream + */ + template T stream_read(_In_ ISequentialStream *stream) + { + static_assert(__is_pod(T), "Read type must be POD"); + T temp{}; + stream_read(stream, &temp, sizeof(temp)); - return temp; -} + return temp; + } -/** Write an exact number of bytes to a stream from a buffer. -Fails if the stream didn't read write the bytes requested. -~~~~ -IStream* source = // ... -ULONG dataBlob = 0; -wil::stream_write(source, dataBlob, sizeof(dataBlob)); -~~~~ -@param stream The stream to which to write at most `size` bytes. -@param data A buffer from which up to `size` bytes will be read -@param size The size, in bytes, of the buffer pointed to by `data` -*/ -inline void stream_write(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) -{ - THROW_IF_FAILED(stream_write_nothrow(stream, data, size)); -} + /** Write an exact number of bytes to a stream from a buffer. + Fails if the stream didn't read write the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + wil::stream_write(source, dataBlob, sizeof(dataBlob)); + ~~~~ + @param stream The stream to which to write at most `size` bytes. + @param data A buffer from which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline void stream_write(_In_ ISequentialStream *stream, _In_reads_bytes_(size) const void *data, + unsigned long size) + { + THROW_IF_FAILED(stream_write_nothrow(stream, data, size)); + } -/** Write a POD type to a stream. -Fails if the stream didn't accept the entire size. -~~~~ -IStream* target = // ... + /** Write a POD type to a stream. + Fails if the stream didn't accept the entire size. + ~~~~ + IStream* target = // ... -MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; -wil::stream_write(target, header) + MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; + wil::stream_write(target, header) -wil::stream_write(target, 16); -~~~~ -@param stream The stream to which to write `thing` -@param thing The POD data type to write to the stream. -*/ -template -inline void stream_write(_In_ ISequentialStream* stream, const T& thing) -{ - stream_write(stream, wistd::addressof(thing), sizeof(thing)); -} + wil::stream_write(target, 16); + ~~~~ + @param stream The stream to which to write `thing` + @param thing The POD data type to write to the stream. + */ + template inline void stream_write(_In_ ISequentialStream *stream, const T &thing) + { + stream_write(stream, wistd::addressof(thing), sizeof(thing)); + } -/** Retrieve the size of this stream, in bytes -~~~~ -IStream* source = // ... -ULONGLONG size = wil::stream_size(source); -~~~~ -@param stream The stream whose size is to be returned in `value` -@return The size, in bytes, reported by `stream` -*/ -inline unsigned long long stream_size(_In_ IStream* stream) -{ - unsigned long long size; - THROW_IF_FAILED(stream_size_nothrow(stream, &size)); + /** Retrieve the size of this stream, in bytes + ~~~~ + IStream* source = // ... + ULONGLONG size = wil::stream_size(source); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @return The size, in bytes, reported by `stream` + */ + inline unsigned long long stream_size(_In_ IStream *stream) + { + unsigned long long size; + THROW_IF_FAILED(stream_size_nothrow(stream, &size)); - return size; -} + return size; + } -/** Seek a stream to an absolute offset -~~~~ -IStream* source = // ... -wil::stream_set_position(source, sizeof(HEADER)); -~~~~ -@param stream The stream whose size is to be returned in `value` -@param offset The offset, in bytes, to seek the stream. -@return The new absolute stream position, in bytes -*/ -inline unsigned long long stream_set_position(_In_ IStream* stream, unsigned long long offset) -{ - unsigned long long landed; - THROW_IF_FAILED(stream_set_position_nothrow(stream, offset, &landed)); - return landed; -} + /** Seek a stream to an absolute offset + ~~~~ + IStream* source = // ... + wil::stream_set_position(source, sizeof(HEADER)); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param offset The offset, in bytes, to seek the stream. + @return The new absolute stream position, in bytes + */ + inline unsigned long long stream_set_position(_In_ IStream *stream, unsigned long long offset) + { + unsigned long long landed; + THROW_IF_FAILED(stream_set_position_nothrow(stream, offset, &landed)); + return landed; + } -/** Seek a relative amount in a stream -~~~~ -IStream* source = // ... -ULONGLONG newPosition = wil::stream_seek_from_current_position(source, 16); -~~~~ -@param stream The stream whose location is to be moved -@param amount The offset, in bytes, to seek the stream. -@return The new absolute stream position, in bytes -*/ -inline unsigned long long stream_seek_from_current_position(_In_ IStream* stream, long long amount) -{ - unsigned long long landed; - THROW_IF_FAILED(stream_seek_from_current_position_nothrow(stream, amount, &landed)); + /** Seek a relative amount in a stream + ~~~~ + IStream* source = // ... + ULONGLONG newPosition = wil::stream_seek_from_current_position(source, 16); + ~~~~ + @param stream The stream whose location is to be moved + @param amount The offset, in bytes, to seek the stream. + @return The new absolute stream position, in bytes + */ + inline unsigned long long stream_seek_from_current_position(_In_ IStream *stream, long long amount) + { + unsigned long long landed; + THROW_IF_FAILED(stream_seek_from_current_position_nothrow(stream, amount, &landed)); - return landed; -} + return landed; + } -/** Determine the current byte position in the stream -~~~~ -IStream* source = // ... -ULONGLONG currentPos = wil::stream_get_position(source); -~~~~ -@param stream The stream whose location is to be moved -@return The current position reported by `stream` -*/ -inline unsigned long long stream_get_position(_In_ IStream* stream) -{ - return stream_seek_from_current_position(stream, 0); -} + /** Determine the current byte position in the stream + ~~~~ + IStream* source = // ... + ULONGLONG currentPos = wil::stream_get_position(source); + ~~~~ + @param stream The stream whose location is to be moved + @return The current position reported by `stream` + */ + inline unsigned long long stream_get_position(_In_ IStream *stream) + { + return stream_seek_from_current_position(stream, 0); + } -/** Moves the stream to absolute position 0 -~~~~ -IStream* source = // ... -wil::stream_reset(source); -ASSERT(wil::stream_get_position(source) == 0); -~~~~ -@param stream The stream whose location is to be moved -*/ -inline void stream_reset(_In_ IStream* stream) -{ - stream_set_position(stream, 0); -} + /** Moves the stream to absolute position 0 + ~~~~ + IStream* source = // ... + wil::stream_reset(source); + ASSERT(wil::stream_get_position(source) == 0); + ~~~~ + @param stream The stream whose location is to be moved + */ + inline void stream_reset(_In_ IStream *stream) + { + stream_set_position(stream, 0); + } -/** Copy data from one stream to another -~~~~ -IStream* source = // ... -IStream* target = // ... -ULONGLONG copied = ; -if (wil::stream_copy_bytes(source, target, sizeof(Header)) < sizeof(Header)) -{ - DoSomethingAboutPartialCopy(); -} -~~~~ -@param source The stream from which to copy at most `amount` bytes -@param target The steam to which to copy at most `amount` bytes -@param amount The maximum number of bytes to copy from `source` to `target` -@return The number of bytes copied between the two streams -*/ -inline unsigned long long stream_copy_bytes(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) -{ - unsigned long long copied; - THROW_IF_FAILED(stream_copy_bytes_nothrow(source, target, amount, &copied)); + /** Copy data from one stream to another + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied = ; + if (wil::stream_copy_bytes(source, target, sizeof(Header)) < sizeof(Header)) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The maximum number of bytes to copy from `source` to `target` + @return The number of bytes copied between the two streams + */ + inline unsigned long long stream_copy_bytes(_In_ IStream *source, _In_ IStream *target, unsigned long long amount) + { + unsigned long long copied; + THROW_IF_FAILED(stream_copy_bytes_nothrow(source, target, amount, &copied)); - return copied; -} + return copied; + } -/** Copy all data from one stream to another -~~~~ -IStream* source = // ... -IStream* target = // ... -ULONGLONG copied = wil::stream_copy_all(source, target); -~~~~ -@param source The stream from which to copy all content -@param target The steam to which to copy all content -@return The number of bytes copied between the two. -*/ -inline unsigned long long stream_copy_all(_In_ IStream* source, _In_ IStream* target) -{ - return stream_copy_bytes(source, target, ULLONG_MAX); -} + /** Copy all data from one stream to another + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied = wil::stream_copy_all(source, target); + ~~~~ + @param source The stream from which to copy all content + @param target The steam to which to copy all content + @return The number of bytes copied between the two. + */ + inline unsigned long long stream_copy_all(_In_ IStream *source, _In_ IStream *target) + { + return stream_copy_bytes(source, target, ULLONG_MAX); + } -/** Copies an exact amount of data from one stream to another, failing otherwise -~~~~ -IStream* source = // ... -IStream* target = // ... -wil::stream_copy_all_nothrow(source, target, sizeof(SOMETHING)); -~~~~ -@param source The stream from which to copy at most `amount` bytes -@param target The steam to which to copy at most `amount` bytes -@param amount The number of bytes to copy from `source` to `target` -*/ -inline void stream_copy_exact(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) -{ - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_copy_bytes(source, target, amount) != amount); -} + /** Copies an exact amount of data from one stream to another, failing otherwise + ~~~~ + IStream* source = // ... + IStream* target = // ... + wil::stream_copy_all_nothrow(source, target, sizeof(SOMETHING)); + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The number of bytes to copy from `source` to `target` + */ + inline void stream_copy_exact(_In_ IStream *source, _In_ IStream *target, unsigned long long amount) + { + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_copy_bytes(source, target, amount) != amount); + } #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) -/** Read a string from a stream and returns an allocated copy -Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format -is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. -Returns a zero-length (but non-null) string if the stream contained a zero-length string. -@code -IStream* source = // ... -wil::unique_cotaskmem_string content = wil::stream_read_string(source); -if (wcscmp(content.get(), L"waffles") == 0) -{ - // Waffles! -} -@endcode -@param source The stream from which to read a string -@param options Controls the behavior when reading a zero-length string -@return An non-null string (but possibly zero length) string read from `source` -*/ -inline wil::unique_cotaskmem_string stream_read_string(_In_ ISequentialStream* source, empty_string_options options = empty_string_options::returns_empty) -{ - wil::unique_cotaskmem_string result; - THROW_IF_FAILED(stream_read_string_nothrow(source, &result, options)); + /** Read a string from a stream and returns an allocated copy + Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format + is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. + Returns a zero-length (but non-null) string if the stream contained a zero-length string. + @code + IStream* source = // ... + wil::unique_cotaskmem_string content = wil::stream_read_string(source); + if (wcscmp(content.get(), L"waffles") == 0) + { + // Waffles! + } + @endcode + @param source The stream from which to read a string + @param options Controls the behavior when reading a zero-length string + @return An non-null string (but possibly zero length) string read from `source` + */ + inline wil::unique_cotaskmem_string stream_read_string( + _In_ ISequentialStream *source, empty_string_options options = empty_string_options::returns_empty) + { + wil::unique_cotaskmem_string result; + THROW_IF_FAILED(stream_read_string_nothrow(source, &result, options)); - return result; -} + return result; + } #endif // __WIL_OBJBASE_H -/** Write a string to a stream -Serializes a string into a stream by putting its length and then the wchar_ts in the string -into the stream. Zero-length strings have their length but no data written. This is the -form expected by IStream_ReadStr and wil::string_read_stream. -~~~~ -IStream* target = // ... -wil::stream_write_string(target, L"Waffles", 3); -~~~~ -@param target The stream to which to write a string -@param source The string to write. Can be null if `toWriteCch` is zero -@param toWriteCch The number of characters to write from source into `target` -*/ -inline void stream_write_string(_In_ ISequentialStream* target, _In_reads_opt_(toWriteCch) const wchar_t* source, _In_ size_t toWriteCch) -{ - THROW_IF_FAILED(stream_write_string_nothrow(target, source, toWriteCch)); -} - -/** Write a string to a stream -Serializes a string into a stream by putting its length and then the wchar_ts in the string -into the stream. Zero-length strings have their length but no data written.This is the -form expected by IStream_ReadStr and wil::string_read_stream. -~~~~ -IStream* target = // ... -wil::stream_write_string(target, L"Waffles"); -~~~~ -@param target The stream to which to write a string -@param source The string to write. When nullptr, a zero-length string is written. -*/ -inline void stream_write_string(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) -{ - THROW_IF_FAILED(stream_write_string_nothrow(target, source, source ? wcslen(source) : 0)); -} - -/** Saves and restores the position of a stream -Useful for potentially reading data from a stream, or being able to read ahead, then reset -back to where one left off, such as conditionally reading content from a stream. -@code -void MaybeConsumeStream(IStream* stream) -{ - // On error, reset the read position in the stream to where we left off - auto saver = wil::stream_position_saver(stream); - auto header = wil::stream_read(stream); - for (ULONG i = 0; i < header.Count; ++i) - { - ProcessElement(wil::stream_read(stream)); - } -} -@endcode -*/ -class stream_position_saver -{ -public: - //! Constructs a saver from the current position of this stream - //! @param stream The stream instance whose position is to be saved. - explicit stream_position_saver(_In_opt_ IStream* stream) : - m_stream(stream), m_position(stream ? stream_get_position(stream) : 0) + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + wil::stream_write_string(target, L"Waffles", 3); + ~~~~ + @param target The stream to which to write a string + @param source The string to write. Can be null if `toWriteCch` is zero + @param toWriteCch The number of characters to write from source into `target` + */ + inline void stream_write_string(_In_ ISequentialStream *target, _In_reads_opt_(toWriteCch) const wchar_t *source, + _In_ size_t toWriteCch) { + THROW_IF_FAILED(stream_write_string_nothrow(target, source, toWriteCch)); } - ~stream_position_saver() + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written.This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + wil::stream_write_string(target, L"Waffles"); + ~~~~ + @param target The stream to which to write a string + @param source The string to write. When nullptr, a zero-length string is written. + */ + inline void stream_write_string(_In_ ISequentialStream *target, _In_opt_z_ const wchar_t *source) { - if (m_stream) + THROW_IF_FAILED(stream_write_string_nothrow(target, source, source ? wcslen(source) : 0)); + } + + /** Saves and restores the position of a stream + Useful for potentially reading data from a stream, or being able to read ahead, then reset + back to where one left off, such as conditionally reading content from a stream. + @code + void MaybeConsumeStream(IStream* stream) + { + // On error, reset the read position in the stream to where we left off + auto saver = wil::stream_position_saver(stream); + auto header = wil::stream_read(stream); + for (ULONG i = 0; i < header.Count; ++i) { - LOG_IF_FAILED(stream_set_position_nothrow(m_stream.get(), m_position)); + ProcessElement(wil::stream_read(stream)); } } - - /** Updates the current position in the stream - @code - // Read a size marker from the stream, then advance that much. - IStream* stream1 = // ... - auto saver = wil::stream_position_saver(stream1); - auto size = wil::stream_read(stream1); - wil::stream_seek_from_current_position(stream, size); - saver.update(); @endcode */ - void update() + class stream_position_saver { - m_position = stream_get_position(m_stream.get()); - } - - //! Returns the current position being saved for the stream - //! @returns The position, in bytes, being saved for the stream - WI_NODISCARD unsigned long long position() const - { - return m_position; - } - - /** Resets the position saver to manage a new stream - Reverts the position of any stream this saver is currently holding a place for. - ~~~~ - IStream* stream1 = // ... - IStream* stream2 = // ... - auto saver = wil::stream_position_saver(stream1); - if (wil::stream_read(stream1).Flags != 0) - { - saver.reset(stream2); // position in stream1 is reverted, now holding stream2 - } - ~~~~ - @param stream The stream whose position is to be saved - */ - void reset(_In_ IStream* stream) - { - reset(); - - m_stream = stream; - m_position = wil::stream_get_position(m_stream.get()); - } - - /** Resets the position of the stream - ~~~~ - IStream* stream1 = // ... - auto saver = wil::stream_position_saver(stream1); - MyType mt = wil::stream_read(stream1); - if (mt.Flags & MyTypeFlags::Extended) - { - saver.reset(); - ProcessExtended(stream1, wil::stream_read(stream1)); - } - else - { - ProcessStandard(stream1, mt); - } - ~~~~ - */ - void reset() - { - if (m_stream) + public: + //! Constructs a saver from the current position of this stream + //! @param stream The stream instance whose position is to be saved. + explicit stream_position_saver(_In_opt_ IStream *stream) + : m_stream(stream), m_position(stream ? stream_get_position(stream) : 0) { - wil::stream_set_position(m_stream.get(), m_position); } - } - /** Stops saving the position of the stream - @code - // The stream has either a standard or extended header, followed by interesting content. - // Read either one, leaving the stream after the headers have been read off. On failure, - // the stream's position is restored. - std::pair get_headers(_In_ IStream* source) - { + ~stream_position_saver() + { + if (m_stream) + { + LOG_IF_FAILED(stream_set_position_nothrow(m_stream.get(), m_position)); + } + } + + /** Updates the current position in the stream + @code + // Read a size marker from the stream, then advance that much. + IStream* stream1 = // ... + auto saver = wil::stream_position_saver(stream1); + auto size = wil::stream_read(stream1); + wil::stream_seek_from_current_position(stream, size); + saver.update(); + @endcode + */ + void update() + { + m_position = stream_get_position(m_stream.get()); + } + + //! Returns the current position being saved for the stream + //! @returns The position, in bytes, being saved for the stream + WI_NODISCARD unsigned long long position() const + { + return m_position; + } + + /** Resets the position saver to manage a new stream + Reverts the position of any stream this saver is currently holding a place for. + ~~~~ + IStream* stream1 = // ... + IStream* stream2 = // ... + auto saver = wil::stream_position_saver(stream1); + if (wil::stream_read(stream1).Flags != 0) + { + saver.reset(stream2); // position in stream1 is reverted, now holding stream2 + } + ~~~~ + @param stream The stream whose position is to be saved + */ + void reset(_In_ IStream *stream) + { + reset(); + + m_stream = stream; + m_position = wil::stream_get_position(m_stream.get()); + } + + /** Resets the position of the stream + ~~~~ + IStream* stream1 = // ... auto saver = wil::stream_position_saver(stream1); MyType mt = wil::stream_read(stream1); - MyTypeExtended mte{}; if (mt.Flags & MyTypeFlags::Extended) { - mte = wil::stream_read(stream1); + saver.reset(); + ProcessExtended(stream1, wil::stream_read(stream1)); + } + else + { + ProcessStandard(stream1, mt); + } + ~~~~ + */ + void reset() + { + if (m_stream) + { + wil::stream_set_position(m_stream.get(), m_position); + } } - saver.dismiss(); - return { mt, mte }; - } - @endcode - */ - void dismiss() - { - m_stream.reset(); - } - stream_position_saver(stream_position_saver&&) = default; - stream_position_saver& operator=(stream_position_saver&&) = default; + /** Stops saving the position of the stream + @code + // The stream has either a standard or extended header, followed by interesting content. + // Read either one, leaving the stream after the headers have been read off. On failure, + // the stream's position is restored. + std::pair get_headers(_In_ IStream* source) + { + auto saver = wil::stream_position_saver(stream1); + MyType mt = wil::stream_read(stream1); + MyTypeExtended mte{}; + if (mt.Flags & MyTypeFlags::Extended) + { + mte = wil::stream_read(stream1); + } + saver.dismiss(); + return { mt, mte }; + } + @endcode + */ + void dismiss() + { + m_stream.reset(); + } - stream_position_saver(const stream_position_saver&) = delete; - void operator=(const stream_position_saver&) = delete; + stream_position_saver(stream_position_saver &&) = default; + stream_position_saver &operator=(stream_position_saver &&) = default; -private: - com_ptr m_stream; - unsigned long long m_position; -}; + stream_position_saver(const stream_position_saver &) = delete; + void operator=(const stream_position_saver &) = delete; + + private: + com_ptr m_stream; + unsigned long long m_position; + }; #endif // WIL_ENABLE_EXCEPTIONS #pragma endregion // stream helpers #if defined(__IObjectWithSite_INTERFACE_DEFINED__) || defined(WIL_DOXYGEN) -/// @cond -namespace details -{ - inline void __stdcall SetSiteNull(IObjectWithSite* objWithSite) + /// @cond + namespace details { - objWithSite->SetSite(nullptr); // break the cycle - } -} // namespace details -/// @endcond - -using unique_set_site_null_call = wil::unique_com_call; - -/** RAII support for managing the site chain. This function sets the site pointer on an object and return an object -that resets it on destruction to break the cycle. -Note, this does not preserve the existing site if there is one (an uncommon case) so only use this when that is not required. -~~~ -auto cleanup = wil::com_set_site(execCommand.get(), serviceProvider->GetAsSite()); -~~~ -Include ocidl.h before wil/com.h to use this. -*/ -WI_NODISCARD inline unique_set_site_null_call com_set_site(_In_opt_ IUnknown* obj, _In_opt_ IUnknown* site) -{ - wil::com_ptr_nothrow objWithSite; - if (site && wil::try_com_copy_to(obj, &objWithSite)) - { - objWithSite->SetSite(site); - } - return unique_set_site_null_call(objWithSite.get()); -} - -/** Iterate over each object in a site chain. Useful for debugging site issues, here is sample use. -~~~ -void OutputDebugSiteChainWatchWindowText(IUnknown* site) -{ - OutputDebugStringW(L"Copy and paste these entries into the Visual Studio Watch Window\n"); - wil::for_each_site(site, [](IUnknown* site) - { - wchar_t msg[64]; - StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site); - OutputDebugStringW(msg); - }); -} -~~~ -*/ - -template -void for_each_site(_In_opt_ IUnknown* siteInput, TLambda&& callback) -{ - wil::com_ptr_nothrow site(siteInput); - while (site) - { - callback(site.get()); - auto objWithSite = site.try_query(); - site.reset(); - if (objWithSite) + inline void __stdcall SetSiteNull(IObjectWithSite *objWithSite) { - objWithSite->GetSite(IID_PPV_ARGS(&site)); + objWithSite->SetSite(nullptr); // break the cycle + } + } // namespace details + /// @endcond + + using unique_set_site_null_call = + wil::unique_com_call; + + /** RAII support for managing the site chain. This function sets the site pointer on an object and return an object + that resets it on destruction to break the cycle. + Note, this does not preserve the existing site if there is one (an uncommon case) so only use this when that is not + required. + ~~~ + auto cleanup = wil::com_set_site(execCommand.get(), serviceProvider->GetAsSite()); + ~~~ + Include ocidl.h before wil/com.h to use this. + */ + WI_NODISCARD inline unique_set_site_null_call com_set_site(_In_opt_ IUnknown *obj, _In_opt_ IUnknown *site) + { + wil::com_ptr_nothrow objWithSite; + if (site && wil::try_com_copy_to(obj, &objWithSite)) + { + objWithSite->SetSite(site); + } + return unique_set_site_null_call(objWithSite.get()); + } + + /** Iterate over each object in a site chain. Useful for debugging site issues, here is sample use. + ~~~ + void OutputDebugSiteChainWatchWindowText(IUnknown* site) + { + OutputDebugStringW(L"Copy and paste these entries into the Visual Studio Watch Window\n"); + wil::for_each_site(site, [](IUnknown* site) + { + wchar_t msg[64]; + StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site); + OutputDebugStringW(msg); + }); + } + ~~~ + */ + + template void for_each_site(_In_opt_ IUnknown *siteInput, TLambda &&callback) + { + wil::com_ptr_nothrow site(siteInput); + while (site) + { + callback(site.get()); + auto objWithSite = site.try_query(); + site.reset(); + if (objWithSite) + { + objWithSite->GetSite(IID_PPV_ARGS(&site)); + } } } -} #endif // __IObjectWithSite_INTERFACE_DEFINED__ #if __cpp_deduction_guides >= 201703L #ifdef WIL_ENABLE_EXCEPTIONS -/// @cond -namespace details -{ - template - struct com_enumerator_next_traits; - - template - struct com_enumerator_next_traits + /// @cond + namespace details { - using Interface = Itf; - using Result = T; - }; + template struct com_enumerator_next_traits; - template - struct com_enumerator_next_traits + template + struct com_enumerator_next_traits + { + using Interface = Itf; + using Result = T; + }; + + template + struct com_enumerator_next_traits + { + using Interface = Itf; + using Result = T; + }; + + template struct has_next + { + template + static auto test(int) -> decltype(wistd::declval()->Next(0, nullptr, nullptr), wistd::true_type{}); + + template static auto test(...) -> wistd::false_type; + + static constexpr bool value = decltype(test(0))::value; + }; + + template constexpr bool has_next_v = has_next::value; + + template struct You_must_specify_Smart_Output_type_explicitly + { + // If you get this error, you must specify a smart pointer type to receive the enumerated objects. + // We deduce the enumerator's output type (the type of the second parameter to the Next method). + // If that type is a COM pointer type (IFoo*), then we use wil::com_ptr. Otherwise, you must + // explicitly specify a smart-object type to receive the enumerated objects as it is not obvious how to + // handle disposing of an enumerated object. For example, if you have an enumerator that enumerates BSTRs, + // you must specify wil::unique_bstr as the smart pointer type to receive the enumerated BSTRs. auto it = + // wil::com_iterator(pEnumBStr); + static_assert(wistd::is_same_v, + "Couldn't deduce a smart pointer type for the enumerator's output. You must explicitly " + "specify a smart-object type to receive the enumerated objects."); + }; + + template struct com_enumerator_traits + { + using Result = typename com_enumerator_next_traits::Result; + + // If the result is a COM pointer type (IFoo*), then we use wil::com_ptr. + // Otherwise, you must explicitly specify a smart output type. + using smart_result = + wistd::conditional_t && + wistd::is_base_of_v<::IUnknown, wistd::remove_pointer_t>, + wil::com_ptr>, + You_must_specify_Smart_Output_type_explicitly>; + }; + } // namespace details + /// @endcond + + template struct com_iterator { - using Interface = Itf; - using Result = T; - }; + using TActualStoredType = + wistd::conditional_t, + typename wil::details::com_enumerator_traits::smart_result, TStoredType>; - template - struct has_next - { - template - static auto test(int) -> decltype(wistd::declval()->Next(0, nullptr, nullptr), wistd::true_type{}); + wil::com_ptr m_enum{}; + TActualStoredType m_currentValue{}; - template - static auto test(...) -> wistd::false_type; + using smart_result = TActualStoredType; + com_iterator(com_iterator &&) = default; + com_iterator(com_iterator const &) = default; + com_iterator &operator=(com_iterator &&) = default; + com_iterator &operator=(com_iterator const &) = default; - static constexpr bool value = decltype(test(0))::value; - }; - - template - constexpr bool has_next_v = has_next::value; - - template - struct You_must_specify_Smart_Output_type_explicitly - { - // If you get this error, you must specify a smart pointer type to receive the enumerated objects. - // We deduce the enumerator's output type (the type of the second parameter to the Next method). - // If that type is a COM pointer type (IFoo*), then we use wil::com_ptr. Otherwise, you must explicitly - // specify a smart-object type to receive the enumerated objects as it is not obvious how to handle disposing - // of an enumerated object. - // For example, if you have an enumerator that enumerates BSTRs, you must specify wil::unique_bstr as the - // smart pointer type to receive the enumerated BSTRs. - // auto it = wil::com_iterator(pEnumBStr); - static_assert( - wistd::is_same_v, - "Couldn't deduce a smart pointer type for the enumerator's output. You must explicitly specify a smart-object type to receive the enumerated objects."); - }; - - template - struct com_enumerator_traits - { - using Result = typename com_enumerator_next_traits::Result; - - // If the result is a COM pointer type (IFoo*), then we use wil::com_ptr. - // Otherwise, you must explicitly specify a smart output type. - using smart_result = wistd::conditional_t< - wistd::is_pointer_v && wistd::is_base_of_v<::IUnknown, wistd::remove_pointer_t>, - wil::com_ptr>, - You_must_specify_Smart_Output_type_explicitly>; - }; -} // namespace details -/// @endcond - -template -struct com_iterator -{ - using TActualStoredType = - wistd::conditional_t, typename wil::details::com_enumerator_traits::smart_result, TStoredType>; - - wil::com_ptr m_enum{}; - TActualStoredType m_currentValue{}; - - using smart_result = TActualStoredType; - com_iterator(com_iterator&&) = default; - com_iterator(com_iterator const&) = default; - com_iterator& operator=(com_iterator&&) = default; - com_iterator& operator=(com_iterator const&) = default; - - com_iterator(IEnumType* enumPtr) : m_enum(enumPtr) - { - FetchNext(); - } - - auto operator->() - { - return wistd::addressof(m_currentValue); - } - - auto& operator*() - { - return m_currentValue; - } - - const auto& operator*() const - { - return m_currentValue; - } - - com_iterator& operator++() - { - // If we're already at the end, don't try to advance. Otherwise, use Next to advance. - if (m_enum) + com_iterator(IEnumType *enumPtr) : m_enum(enumPtr) { FetchNext(); } - return *this; - } - - bool operator!=(com_iterator const& other) const - { - return !(*this == other); - } - - bool operator==(com_iterator const& other) const - { - return (m_enum.get() == other.m_enum.get()); - } - -private: - void FetchNext() - { - if (m_enum) + auto operator->() { - // we cannot say m_currentValue = {} because com_ptr has 2 operator= overloads: one for T* and one for nullptr_t - m_currentValue = TActualStoredType{}; - auto hr = m_enum->Next(1, &m_currentValue, nullptr); - if (hr == S_FALSE) + return wistd::addressof(m_currentValue); + } + + auto &operator*() + { + return m_currentValue; + } + + const auto &operator*() const + { + return m_currentValue; + } + + com_iterator &operator++() + { + // If we're already at the end, don't try to advance. Otherwise, use Next to advance. + if (m_enum) { - m_enum = nullptr; + FetchNext(); } - else + + return *this; + } + + bool operator!=(com_iterator const &other) const + { + return !(*this == other); + } + + bool operator==(com_iterator const &other) const + { + return (m_enum.get() == other.m_enum.get()); + } + + private: + void FetchNext() + { + if (m_enum) { - THROW_IF_FAILED_MSG(hr, "Failed to get next"); + // we cannot say m_currentValue = {} because com_ptr has 2 operator= overloads: one for T* and one for + // nullptr_t + m_currentValue = TActualStoredType{}; + auto hr = m_enum->Next(1, &m_currentValue, nullptr); + if (hr == S_FALSE) + { + m_enum = nullptr; + } + else + { + THROW_IF_FAILED_MSG(hr, "Failed to get next"); + } } } - } -}; - -// CTAD for com_iterator - -template -com_iterator(IEnumType*) -> com_iterator; - -template , int> = 0> -WI_NODISCARD auto make_range(IEnumXxx* enumPtr) -{ - using TActualStoredType = - wistd::conditional_t, typename wil::details::com_enumerator_traits::smart_result, TStoredType>; - - struct iterator_range - { - - static_assert(!wistd::is_same_v, "You must specify a type to receive the enumerated objects."); - - // the stored type must be constructible from the output type of the enumerator - static_assert( - wistd::is_constructible_v::Result>, - "The type you specified cannot be converted to the enumerator's output type."); - - using enumerator_type = com_iterator; - - wil::com_ptr m_enumerator{}; - iterator_range(IEnumXxx* enumPtr) : m_enumerator(enumPtr) - { - } - - WI_NODISCARD auto begin() - { - return enumerator_type(m_enumerator.get()); - } - - WI_NODISCARD constexpr auto end() const noexcept - { - return enumerator_type(nullptr); - } }; - return iterator_range(enumPtr); -} + // CTAD for com_iterator -template >> -auto make_range(const wil::com_ptr& e) -{ - using Enumerated = typename wil::details::com_enumerator_traits::smart_result; - return wil::make_range(e.get()); -} + template com_iterator(IEnumType *) -> com_iterator; + + template , int> = 0> + WI_NODISCARD auto make_range(IEnumXxx *enumPtr) + { + using TActualStoredType = + wistd::conditional_t, + typename wil::details::com_enumerator_traits::smart_result, TStoredType>; + + struct iterator_range + { + + static_assert(!wistd::is_same_v, + "You must specify a type to receive the enumerated objects."); + + // the stored type must be constructible from the output type of the enumerator + static_assert(wistd::is_constructible_v::Result>, + "The type you specified cannot be converted to the enumerator's output type."); + + using enumerator_type = com_iterator; + + wil::com_ptr m_enumerator{}; + iterator_range(IEnumXxx *enumPtr) : m_enumerator(enumPtr) + { + } + + WI_NODISCARD auto begin() + { + return enumerator_type(m_enumerator.get()); + } + + WI_NODISCARD constexpr auto end() const noexcept + { + return enumerator_type(nullptr); + } + }; + + return iterator_range(enumPtr); + } + + template >> + auto make_range(const wil::com_ptr &e) + { + using Enumerated = typename wil::details::com_enumerator_traits::smart_result; + return wil::make_range(e.get()); + } #ifdef __IShellItemArray_INTERFACE_DEFINED__ -inline auto make_range(IShellItemArray* sia) -{ - wil::com_ptr enumShellItems; - THROW_IF_FAILED(sia->EnumItems(&enumShellItems)); - return make_range(enumShellItems); -} + inline auto make_range(IShellItemArray *sia) + { + wil::com_ptr enumShellItems; + THROW_IF_FAILED(sia->EnumItems(&enumShellItems)); + return make_range(enumShellItems); + } -inline auto make_range(const wil::com_ptr& sia) -{ - return make_range(sia.get()); -} + inline auto make_range(const wil::com_ptr &sia) + { + return make_range(sia.get()); + } #endif // __IShellItemArray_INTERFACE_DEFINED__ #endif // __cpp_deduction_guides >= 201703L @@ -3348,102 +3395,103 @@ inline auto make_range(const wil::com_ptr& sia) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -namespace details -{ - inline void CoDisableCallCancellationNull() + namespace details { - (void)::CoDisableCallCancellation(nullptr); - } -} // namespace details - -/** RAII support for making cross-apartment (or cross process) COM calls with a timeout applied to them. - * When this is active any timed out calls will fail with an RPC error code such as RPC_E_CALL_CANCELED. - * This is a shared timeout that applies to all calls made on the current thread for the lifetime of - * the wil::com_timeout object. - * A periodic timer is used to cancel calls that have been blocked too long. If multiple blocking calls - * are made, and multiple are timing out, then there may be a total delay of (timeoutInMilliseconds * N) - * where N is the number of calls. -~~~ -{ - auto timeout = wil::com_timeout(5000); - remote_object->BlockingCOMCall(); - remote_object->AnotherBlockingCOMCall(); -} -~~~ -*/ -template -class com_timeout_t -{ -public: - com_timeout_t(DWORD timeoutInMilliseconds) : m_threadId(GetCurrentThreadId()) - { - const HRESULT cancelEnablementResult = CoEnableCallCancellation(nullptr); - err_policy::HResult(cancelEnablementResult); - if (SUCCEEDED(cancelEnablementResult)) + inline void CoDisableCallCancellationNull() { - m_ensureDisable.activate(); + (void)::CoDisableCallCancellation(nullptr); + } + } // namespace details - m_timer.reset(CreateThreadpoolTimer(&com_timeout_t::timer_callback, this, nullptr)); - err_policy::LastErrorIfFalse(static_cast(m_timer)); - if (m_timer) + /** RAII support for making cross-apartment (or cross process) COM calls with a timeout applied to them. + * When this is active any timed out calls will fail with an RPC error code such as RPC_E_CALL_CANCELED. + * This is a shared timeout that applies to all calls made on the current thread for the lifetime of + * the wil::com_timeout object. + * A periodic timer is used to cancel calls that have been blocked too long. If multiple blocking calls + * are made, and multiple are timing out, then there may be a total delay of (timeoutInMilliseconds * N) + * where N is the number of calls. + ~~~ + { + auto timeout = wil::com_timeout(5000); + remote_object->BlockingCOMCall(); + remote_object->AnotherBlockingCOMCall(); + } + ~~~ + */ + template class com_timeout_t + { + public: + com_timeout_t(DWORD timeoutInMilliseconds) : m_threadId(GetCurrentThreadId()) + { + const HRESULT cancelEnablementResult = CoEnableCallCancellation(nullptr); + err_policy::HResult(cancelEnablementResult); + if (SUCCEEDED(cancelEnablementResult)) { - FILETIME ft = filetime::get_system_time(); - ft = filetime::add(ft, filetime::convert_msec_to_100ns(timeoutInMilliseconds)); - SetThreadpoolTimer(m_timer.get(), &ft, timeoutInMilliseconds, 0); + m_ensureDisable.activate(); + + m_timer.reset(CreateThreadpoolTimer(&com_timeout_t::timer_callback, this, nullptr)); + err_policy::LastErrorIfFalse(static_cast(m_timer)); + if (m_timer) + { + FILETIME ft = filetime::get_system_time(); + ft = filetime::add(ft, filetime::convert_msec_to_100ns(timeoutInMilliseconds)); + SetThreadpoolTimer(m_timer.get(), &ft, timeoutInMilliseconds, 0); + } } } - } - bool timed_out() const - { - return m_timedOut; - } - - operator bool() const noexcept - { - // All construction calls must succeed to provide us with a non-null m_timer value. - return static_cast(m_timer); - } - -private: - // Disable use of new as this class should only be declared on the stack, never the heap. - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - - // not copyable or movable because the timer_callback receives "this" - com_timeout_t(com_timeout_t const&) = delete; - void operator=(com_timeout_t const&) = delete; - - static void __stdcall timer_callback(PTP_CALLBACK_INSTANCE /*instance*/, PVOID context, PTP_TIMER /*timer*/) - { - // The timer is waited upon during destruction so it is safe to rely on the this pointer in context. - com_timeout_t* self = static_cast(context); - if (SUCCEEDED(CoCancelCall(self->m_threadId, 0))) + bool timed_out() const { - self->m_timedOut = true; + return m_timedOut; } - } - wil::unique_call m_ensureDisable{}; - DWORD m_threadId{}; - bool m_timedOut{}; + operator bool() const noexcept + { + // All construction calls must succeed to provide us with a non-null m_timer value. + return static_cast(m_timer); + } - // The threadpool timer goes last so that it destructs first, waiting until the timer callback has completed. - wil::unique_threadpool_timer_nocancel m_timer; -}; + private: + // Disable use of new as this class should only be declared on the stack, never the heap. + void *operator new(size_t) = delete; + void *operator new[](size_t) = delete; -// Error-policy driven forms of com_timeout + // not copyable or movable because the timer_callback receives "this" + com_timeout_t(com_timeout_t const &) = delete; + void operator=(com_timeout_t const &) = delete; + + static void __stdcall timer_callback(PTP_CALLBACK_INSTANCE /*instance*/, PVOID context, PTP_TIMER /*timer*/) + { + // The timer is waited upon during destruction so it is safe to rely on the this pointer in context. + com_timeout_t *self = static_cast(context); + if (SUCCEEDED(CoCancelCall(self->m_threadId, 0))) + { + self->m_timedOut = true; + } + } + + wil::unique_call + m_ensureDisable{}; + DWORD m_threadId{}; + bool m_timedOut{}; + + // The threadpool timer goes last so that it destructs first, waiting until the timer callback has completed. + wil::unique_threadpool_timer_nocancel m_timer; + }; + + // Error-policy driven forms of com_timeout #ifdef WIL_ENABLE_EXCEPTIONS -//! COM timeout, errors throw exceptions (see @ref com_timeout_t for details) -using com_timeout = com_timeout_t; + //! COM timeout, errors throw exceptions (see @ref com_timeout_t for details) + using com_timeout = com_timeout_t; #endif -//! COM timeout, errors return error codes (see @ref com_timeout_t for details) -using com_timeout_nothrow = com_timeout_t; + //! COM timeout, errors return error codes (see @ref com_timeout_t for details) + using com_timeout_nothrow = com_timeout_t; -//! COM timeout, errors fail-fast (see @ref com_timeout_t for details) -using com_timeout_failfast = com_timeout_t; + //! COM timeout, errors fail-fast (see @ref com_timeout_t for details) + using com_timeout_failfast = com_timeout_t; #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com_apartment_variable.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com_apartment_variable.h index 8103150..5d7d301 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com_apartment_variable.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/com_apartment_variable.h @@ -31,459 +31,458 @@ 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; - -struct apartment_variable_platform -{ - static unsigned long long GetApartmentId() + // 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{}; - FAIL_FAST_IF_FAILED(RoGetApartmentIdentifier(&apartmentId)); - return apartmentId; + return RoGetApartmentIdentifier(&apartmentId) != HRESULT_FROM_WIN32(ERROR_API_UNAVAILABLE); } - static auto RegisterForApartmentShutdown(IApartmentShutdown* observer) + // 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; + + struct apartment_variable_platform { - 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(moduleAddress), &moduleHandle) != FALSE; - } - - struct any_maker_base - { - std::any (*adapter)(void*); - void* inner; - - WI_NODISCARD std::any operator()() const + static unsigned long long GetApartmentId() { - return adapter(inner); + 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; }; - template - struct any_maker : any_maker_base + enum class apartment_variable_leak_action { - any_maker() - { - adapter = [](auto) -> std::any { - return T{}; - }; - } - - any_maker(T (*maker)()) - { - adapter = [](auto maker) -> std::any { - return reinterpret_cast(maker)(); - }; - inner = reinterpret_cast(maker); - } - - template - any_maker(F&& f) - { - adapter = [](auto maker) -> std::any { - return reinterpret_cast(maker)[0](); - }; - inner = std::addressof(f); - } + fail_fast, + ignore }; - template - struct apartment_variable_base + // "pins" the current module in memory by incrementing the module reference count and leaking that. + inline void ensure_module_stays_loaded() { - inline static winrt::slim_mutex s_lock; + 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; + }); + } - struct apartment_variable_storage + /// @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 { - apartment_variable_storage(apartment_variable_storage&& other) noexcept = default; - apartment_variable_storage(const apartment_variable_storage& other) = delete; + wil::unique_hmodule moduleHandle; + return GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(moduleAddress), + &moduleHandle) != FALSE; + } - apartment_variable_storage(typename test_hook::shutdown_type&& cookie_) : cookie(std::move(cookie_)) + struct any_maker_base + { + std::any (*adapter)(void *); + void *inner; + + WI_NODISCARD std::any operator()() const { + return adapter(inner); } - - 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*, std::any> variables; }; - // Apartment id -> variables storage. - inline static wil::object_without_destructor_on_shutdown> s_apartmentStorage; - - constexpr apartment_variable_base() = default; - ~apartment_variable_base() + template struct any_maker : any_maker_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) + any_maker() { - clear_all_apartments_async(); + adapter = [](auto) -> std::any { return T{}; }; } - if constexpr (leak_action == apartment_variable_leak_action::fail_fast) + any_maker(T (*maker)()) { - if (isGlobal && !ProcessShutdownInProgress()) + adapter = [](auto maker) -> std::any { return reinterpret_cast(maker)(); }; + inner = reinterpret_cast(maker); + } + + template any_maker(F &&f) + { + adapter = [](auto maker) -> std::any { return reinterpret_cast(maker)[0](); }; + inner = std::addressof(f); + } + }; + + template + 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_)) { - // 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 - // - // For DLLs, if this is expected, disable this fail fast using - // wil::apartment_variable - // - // 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 - { - 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(); - } + 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 *, std::any> variables; }; - auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make().get()); - return &s_apartmentStorage.get() - .insert({test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration))}) - .first->second; + + // Apartment id -> variables storage. + inline static wil::object_without_destructor_on_shutdown< + std::unordered_map> + 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 + // + // For DLLs, if this is expected, disable this fail fast using + // wil::apartment_variable + // + // 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 + { + 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().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 std::any &get_or_create(any_maker &&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 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 + struct apartment_variable : details::apartment_variable_base + { + using base = details::apartment_variable_base; + + constexpr apartment_variable() = default; + + // Get current value or throw if no value has been set. + T &get_existing() + { + return std::any_cast(base::get_existing()); } - // get current value or custom-construct one on demand - template - std::any& get_or_create(any_maker&& creator) + // Get current value or default-construct one on demand. + T &get_or_create() { - apartment_variable_storage* variable_storage = nullptr; + return std::any_cast(base::get_or_create(details::any_maker())); + } - { // 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 current value or custom-construct one on demand. + template T &get_or_create(F &&f) + { + return std::any_cast(base::get_or_create(details::any_maker(std::forward(f)))); } // get pointer to current value or nullptr if no value has been set - std::any* get_if() + T *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; + return std::any_cast(base::get_if()); } // replace or create the current value, fail fasts if the value is not already stored - void set(std::any value) + template void set(V &&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); - } + return base::set(std::forward(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()); - } - } - } + // Clear the value in the current apartment. + using base::clear; - 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). + // Asynchronously clear the value in all apartments it is present in. + using base::clear_all_apartments_async; - std::vector 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; - } + // 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 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 -struct apartment_variable : details::apartment_variable_base -{ - using base = details::apartment_variable_base; - - constexpr apartment_variable() = default; - - // Get current value or throw if no value has been set. - T& get_existing() - { - return std::any_cast(base::get_existing()); - } - - // Get current value or default-construct one on demand. - T& get_or_create() - { - return std::any_cast(base::get_or_create(details::any_maker())); - } - - // Get current value or custom-construct one on demand. - template - T& get_or_create(F&& f) - { - return std::any_cast(base::get_or_create(details::any_maker(std::forward(f)))); - } - - // get pointer to current value or nullptr if no value has been set - T* get_if() - { - return std::any_cast(base::get_if()); - } - - // replace or create the current value, fail fasts if the value is not already stored - template - void set(V&& value) - { - return base::set(std::forward(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 diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/common.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/common.h index d69f4ea..0cb5ae1 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/common.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/common.h @@ -293,7 +293,8 @@ static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid 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 +#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 @@ -342,12 +343,12 @@ deduce whether or not the STL is available and can be safely used. #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 +// 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_BEGIN \ + inline namespace __WI_ITR_NAMESPACE \ { #define __WI_ITR_NAMESPACE_END } #else @@ -366,30 +367,30 @@ classes and methods from WIL, define this macro ahead of including the first WIL #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. */ +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 +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' +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 @@ -398,8 +399,8 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th // 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::value, void*> = nullptr -#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t::value, void*> = nullptr +#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t::value, void *> = nullptr +#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t::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 @@ -423,27 +424,30 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th //! 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. +//! 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. +//! 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 +//! 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 +//! 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): @@ -458,8 +462,9 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th //! 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>(val) //! Validates that exactly ONE bit is set in compile-time constant `flag` -#define WI_StaticAssertSingleBitSet(flag) \ - static_cast(::wil::details::verify_single_flag_helper(WI_EnumValue(flag))>::value) +#define WI_StaticAssertSingleBitSet(flag) \ + static_cast( \ + ::wil::details::verify_single_flag_helper(WI_EnumValue(flag))>::value) //! @name Bitwise manipulation macros //! @{ @@ -469,13 +474,13 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th //! 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); \ - } \ +#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`. @@ -483,19 +488,21 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th //! 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); \ - } \ +#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`. +//! 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`. @@ -510,14 +517,16 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th //! 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(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast(0)) +#define WI_IsAnyFlagSet(val, flags) \ + (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) != \ + static_cast(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(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast(0)) +#define WI_AreAllFlagsClear(val, flags) \ + (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) == \ + static_cast(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`. @@ -529,8 +538,8 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th #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`. +//! 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 @@ -561,18 +570,18 @@ desktop APIs. Building this functionality as `#IFDEF`s within functions would c 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(fn()); \ - } \ +#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \ + extern "C" \ + { \ + __declspec(selectany) unsigned char g_header_init_##name = static_cast(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(fn()); \ - } \ +#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \ + extern "C" \ + { \ + __declspec(selectany) unsigned char g_header_init_##name = static_cast(fn()); \ + } \ __pragma(comment(linker, "/INCLUDE:g_header_init_" #name)) #else #error linker pragma must include g_header_init variation @@ -587,331 +596,309 @@ the namespace directly (example: `wil::srwlock lock;`) without a using statement statement for wil to avoid introducing potential name collisions between wil and other namespaces. */ namespace wil { -/// @cond -namespace details -{ - template - class pointer_range + /// @cond + namespace details { - public: - pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_) + template class pointer_range { - } - WI_NODISCARD T begin() const - { - return m_begin; - } - WI_NODISCARD T end() const - { - return m_end; - } + 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 + 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 -details::pointer_range make_range(T begin, T end) -{ - return details::pointer_range(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 -details::pointer_range make_range(T begin, size_t count) -{ - return details::pointer_range(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 -inline void assign_to_opt_param(_Out_opt_ T* outParam, T val) -{ - if (outParam != nullptr) + /** Enables using range-based for between a begin and end object pointer. + ~~~~ + for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { } + ~~~~ */ + template details::pointer_range make_range(T begin, T end) { - *outParam = val; + return details::pointer_range(begin, end); } -} -/** Assign NULL to an optional output pointer parameter. -Makes code more concise by removing trivial `if (outParam)` blocks. */ -template -inline void assign_null_to_opt_param(_Out_opt_ T* outParam) -{ - if (outParam != nullptr) + /** 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 details::pointer_range make_range(T begin, size_t count) { - *outParam = nullptr; + return details::pointer_range(begin, begin + count); } -} -//! @} // end output parameter helpers -/** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation. -Example usage: -~~~~ -template -struct FeatureRequiredBy -{ - static const bool enabled = wil::variadic_logical_or::enabled...>::value; -}; -~~~~ */ -template -struct variadic_logical_or; -/// @cond -template <> -struct variadic_logical_or<> : wistd::false_type -{ -}; -template -struct variadic_logical_or : wistd::true_type -{ -}; -template -struct variadic_logical_or : variadic_logical_or::type -{ -}; -/// @endcond + //! @defgroup outparam Output Parameters + //! Improve the conciseness of assigning values to optional output parameters. + //! @{ -/// @cond -namespace details -{ - template - struct verify_single_flag_helper + /** Assign the given value to an optional output parameter. + Makes code more concise by removing trivial `if (outParam)` blocks. */ + template inline void assign_to_opt_param(_Out_opt_ T *outParam, T val) { - static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found"); - static const unsigned long long value = flag; + if (outParam != nullptr) + { + *outParam = val; + } + } + + /** Assign NULL to an optional output pointer parameter. + Makes code more concise by removing trivial `if (outParam)` blocks. */ + template 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 + struct FeatureRequiredBy + { + static const bool enabled = wil::variadic_logical_or::enabled...>::value; }; -} // namespace details -/// @endcond + ~~~~ */ + template struct variadic_logical_or; + /// @cond + template <> struct variadic_logical_or<> : wistd::false_type + { + }; + template struct variadic_logical_or : wistd::true_type + { + }; + template struct variadic_logical_or : variadic_logical_or::type + { + }; + /// @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. -//! @{ + /// @cond + namespace details + { + template 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 -/** 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 -_Post_satisfies_(return == static_cast(val)) inline constexpr bool verify_bool(const T& val) WI_NOEXCEPT -{ - return static_cast(val); -} + //! @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. + //! @{ -template -inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT -{ - static_assert(!wistd::is_same::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected"); - return false; -} + /** 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 + _Post_satisfies_(return == static_cast(val)) inline constexpr bool verify_bool(const T &val) WI_NOEXCEPT + { + return static_cast(val); + } -template <> -_Post_satisfies_(return == val) inline constexpr bool verify_bool(bool val) WI_NOEXCEPT -{ - return val; -} + template inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected"); + return false; + } -template <> -_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool(int val) WI_NOEXCEPT -{ - return (val != 0); -} + template <> _Post_satisfies_(return == val) inline constexpr bool verify_bool(bool val) WI_NOEXCEPT + { + return val; + } -template <> -_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool(unsigned char val) WI_NOEXCEPT -{ - return (val != 0); -} + template <> _Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool(int 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 -_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::value), "Wrong Type: BOOL expected"); - return val; -} + template <> + _Post_satisfies_(return == + (val != 0)) inline constexpr bool verify_bool(unsigned char val) WI_NOEXCEPT + { + return (val != 0); + } -/** 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. + /** 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 _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::value), "Wrong Type: BOOL expected"); + return val; + } -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(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId)); -~~~~ -@param hr The HRESULT returning expression -@return An HRESULT representing the evaluation of `val`. */ -template -_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::value, "Wrong Type: HRESULT expected"); - return hr; -} + /** 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. -/** 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(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0)); -@endcode -@param status The NTSTATUS returning expression -@return An NTSTATUS representing the evaluation of `val`. */ -template -_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::value, "Wrong Type: NTSTATUS expected"); - return status; -} + 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(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId)); + ~~~~ + @param hr The HRESULT returning expression + @return An HRESULT representing the evaluation of `val`. */ + template _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::value, "Wrong Type: HRESULT expected"); + return hr; + } -/** 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 -_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::value || wistd::is_same::value, - "Wrong Type: Win32 error code (long / unsigned long) expected"); - return error; -} -/// @} // end type validation routines + /** 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(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0)); + @endcode + @param status The NTSTATUS returning expression + @return An NTSTATUS representing the evaluation of `val`. */ + template _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::value, "Wrong Type: NTSTATUS expected"); + return status; + } -/// @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(val) \ - : sizeof(val) == 2 ? static_cast(val) \ - : sizeof(val) == 4 ? static_cast(val) \ + /** 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 _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::value || wistd::is_same::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(val) \ + : sizeof(val) == 2 ? static_cast(val) \ + : sizeof(val) == 4 ? static_cast(val) \ : static_cast(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 - __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags) - { - return ((val & flags) == static_cast(flags)); - } + template + __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags) + { + return ((val & flags) == static_cast(flags)); + } - template - __forceinline constexpr bool IsSingleFlagSetHelper(TVal val) - { - return __WI_IS_SINGLE_FLAG_SET(val); - } + template __forceinline constexpr bool IsSingleFlagSetHelper(TVal val) + { + return __WI_IS_SINGLE_FLAG_SET(val); + } - template - __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val) - { - return ((val == static_cast>(0)) || IsSingleFlagSetHelper(val)); - } + template __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val) + { + return ((val == static_cast>(0)) || IsSingleFlagSetHelper(val)); + } - template - __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags) - { - val = static_cast>((val & ~mask) | (flags & mask)); - } + template + __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal &val, TMask mask, TFlags flags) + { + val = static_cast>((val & ~mask) | (flags & mask)); + } - template - struct variable_size; + template struct variable_size; - template <> - struct variable_size<1> - { - using type = unsigned char; - }; + template <> struct variable_size<1> + { + using type = unsigned char; + }; - template <> - struct variable_size<2> - { - using type = unsigned short; - }; + template <> struct variable_size<2> + { + using type = unsigned short; + }; - template <> - struct variable_size<4> - { - using type = unsigned long; - }; + template <> struct variable_size<4> + { + using type = unsigned long; + }; - template <> - struct variable_size<8> - { - using type = unsigned long long; - }; + template <> struct variable_size<8> + { + using type = unsigned long long; + }; - template - struct variable_size_mapping - { - using type = typename variable_size::type; - }; -} // namespace details -/// @endcond + template struct variable_size_mapping + { + using type = typename variable_size::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 -using integral_from_enum = typename details::variable_size_mapping::type; + /** 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 using integral_from_enum = typename details::variable_size_mapping::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); + //! 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) diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/coroutine.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/coroutine.h index 6ce9a05..04c63e5 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/coroutine.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/coroutine.h @@ -162,541 +162,521 @@ #include #include #include +#include #include #include -#include 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 -struct task; + // 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 struct task; -template -struct com_task; + template 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; + // 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 -struct task_promise; + template 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 -struct result_wrapper -{ - T value; - T get_value() - { - return wistd::forward(value); - } -}; - -template <> -struct result_wrapper -{ - void get_value() - { - } -}; - -// The result_holder is basically a -// std::variant -// but with these extra quirks: -// * The only valid transition is monotype -> something-else. -// Consequently, it does not have valueless_by_exception. - -template -struct result_holder -{ - // The content of the result_holder - // depends on the result_status: + // 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. // - // empty: No active member. - // value: Active member is wrap. - // error: Active member is error. - enum class result_status + // 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 struct result_wrapper { - empty, - value, - error + T value; + T get_value() + { + return wistd::forward(value); + } }; - result_status status{result_status::empty}; - union variant + template <> struct result_wrapper { - variant() + void get_value() { } - ~variant() + }; + + // The result_holder is basically a + // std::variant + // but with these extra quirks: + // * The only valid transition is monotype -> something-else. + // Consequently, it does not have valueless_by_exception. + + template 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 { - } - result_wrapper 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 - void emplace_value(Args&&... args) - { - WI_ASSERT(status == result_status::empty); - new (wistd::addressof(result.wrap)) result_wrapper{wistd::forward(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 and -// task_promise 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 -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(1); - } - static void* abandoned_ptr() - { - return reinterpret_cast(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 m_waiting{running_ptr()}; - result_holder m_holder; - - // Make it easier to access our CRTP derived class. - using Promise = task_promise; - auto as_promise() noexcept - { - return static_cast(this); - } - - // Make it easier to access the coroutine handle. - auto as_handle() noexcept - { - return __WI_COROUTINE_NAMESPACE::coroutine_handle::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 - void emplace_value(Args&&... args) - { - m_holder.emplace_value(wistd::forward(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); - } - }; + empty, + value, + error }; - 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(); - } + result_status status{result_status::empty}; + union variant { + variant() + { + } + ~variant() + { + } + result_wrapper wrap; + std::exception_ptr error; + } result; - 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(waiting) > 16); + // 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}; - 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 -struct task_promise : promise_base -{ - template - void return_value(U&& value) - { - this->emplace_value(wistd::forward(value)); - } - - template - wistd::enable_if_t, Dummy> return_value(T const& value) - { - this->emplace_value(value); - } -}; - -template <> -struct task_promise : promise_base -{ - void return_void() - { - this->emplace_value(); - } -}; - -template -struct promise_deleter -{ - void operator()(promise_base* promise) const noexcept - { - promise->abandon(); - } -}; - -template -using promise_ptr = wistd::unique_ptr, promise_deleter>; - -template -struct agile_awaiter -{ - agile_awaiter(promise_ptr&& initial) : promise(wistd::move(initial)) - { - } - - promise_ptr 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 -struct task_base -{ - auto resume_any_thread() && noexcept - { - return agile_awaiter{wistd::move(promise)}; - } - - // You must #include before 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() + // 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 void emplace_value(Args &&...args) { + WI_ASSERT(status == result_status::empty); + new (wistd::addressof(result.wrap)) result_wrapper{wistd::forward(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(); + } } }; - cannot_await_lvalue_use_std_move operator co_await() & = delete; - // You must #include (usually via ) to enable synchronous waiting. - decltype(auto) get() &&; - -protected: - task_base(task_promise* initial = nullptr) noexcept : promise(initial) + // Most of the work is done in the promise_base, + // It is a CRTP-like base class for task_promise and + // task_promise 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 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. - template - D& assign(D* self, task_base&& other) noexcept + // Special values for m_waiting. + static void *running_ptr() + { + return nullptr; + } + static void *completed_ptr() + { + return reinterpret_cast(1); + } + static void *abandoned_ptr() + { + return reinterpret_cast(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 m_waiting{running_ptr()}; + result_holder m_holder; + + // Make it easier to access our CRTP derived class. + using Promise = task_promise; + auto as_promise() noexcept + { + return static_cast(this); + } + + // Make it easier to access the coroutine handle. + auto as_handle() noexcept + { + return __WI_COROUTINE_NAMESPACE::coroutine_handle::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 void emplace_value(Args &&...args) + { + m_holder.emplace_value(wistd::forward(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(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 struct task_promise : promise_base { - static_cast(*this) = wistd::move(other); - return *self; - } + template void return_value(U &&value) + { + this->emplace_value(wistd::forward(value)); + } -private: - promise_ptr promise; + template + wistd::enable_if_t, Dummy> return_value(T const &value) + { + this->emplace_value(value); + } + }; - static void __stdcall wake_by_address(void* completed); -}; + template <> struct task_promise : promise_base + { + void return_void() + { + this->emplace_value(); + } + }; + + template struct promise_deleter + { + void operator()(promise_base *promise) const noexcept + { + promise->abandon(); + } + }; + + template using promise_ptr = wistd::unique_ptr, promise_deleter>; + + template struct agile_awaiter + { + agile_awaiter(promise_ptr &&initial) : promise(wistd::move(initial)) + { + } + + promise_ptr 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 struct task_base + { + auto resume_any_thread() && noexcept + { + return agile_awaiter{wistd::move(promise)}; + } + + // You must #include before 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 (usually via ) to enable synchronous waiting. + decltype(auto) get() &&; + + protected: + task_base(task_promise *initial = nullptr) noexcept : promise(initial) + { + } + + template D &assign(D *self, task_base &&other) noexcept + { + static_cast(*this) = wistd::move(other); + return *self; + } + + private: + promise_ptr 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 -struct task : details::coro::task_base -{ - using base = details::coro::task_base; - // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit conversion. - task(details::coro::task_promise* initial = nullptr) noexcept : base(initial) + // Must write out both classes separately + // Cannot use deduction guides with alias template type prior to C++20. + template struct task : details::coro::task_base { - } - explicit task(base&& other) noexcept : base(wistd::move(other)) - { - } - task& operator=(base&& other) noexcept - { - return base::assign(this, wistd::move(other)); - } + using base = details::coro::task_base; + // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit + // conversion. + task(details::coro::task_promise *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; + using base::operator co_await; - auto operator co_await() && noexcept - { - return wistd::move(*this).resume_any_thread(); - } -}; + auto operator co_await() && noexcept + { + return wistd::move(*this).resume_any_thread(); + } + }; -template -struct com_task : details::coro::task_base -{ - using base = details::coro::task_base; - // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit conversion. - com_task(details::coro::task_promise* initial = nullptr) noexcept : base(initial) + template struct com_task : details::coro::task_base { - } - 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 = details::coro::task_base; + // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit + // conversion. + com_task(details::coro::task_promise *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; + using base::operator co_await; - auto operator co_await() && noexcept - { - // You must #include before to enable non-agile awaiting. - return wistd::move(*this).resume_same_apartment(); - } -}; + auto operator co_await() && noexcept + { + // You must #include before to enable non-agile awaiting. + return wistd::move(*this).resume_same_apartment(); + } + }; -template -task(com_task&&) -> task; -template -com_task(task&&) -> com_task; + template task(com_task &&) -> task; + template com_task(task &&) -> com_task; } // namespace wil -template -struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> +template struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> { using promise_type = wil::details::coro::task_promise; }; -template -struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> +template struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> { using promise_type = wil::details::coro::task_promise; }; @@ -709,30 +689,28 @@ struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> namespace wil::details::coro { -template -decltype(auto) task_base::get() && -{ - if (!promise->client_await_ready()) + template decltype(auto) task_base::get() && { - bool completed = false; - if (promise->client_await_suspend(&completed, wake_by_address)) + if (!promise->client_await_ready()) { - bool pending = false; - while (!completed) + bool completed = false; + if (promise->client_await_suspend(&completed, wake_by_address)) { - WaitOnAddress(&completed, &pending, sizeof(pending), INFINITE); + bool pending = false; + while (!completed) + { + WaitOnAddress(&completed, &pending, sizeof(pending), INFINITE); + } } } + return std::exchange(promise, {})->client_await_resume(); } - return std::exchange(promise, {})->client_await_resume(); -} -template -void __stdcall task_base::wake_by_address(void* completed) -{ - *reinterpret_cast(completed) = true; - WakeByAddressSingle(completed); -} + template void __stdcall task_base::wake_by_address(void *completed) + { + *reinterpret_cast(completed) = true; + WakeByAddressSingle(completed); + } } // namespace wil::details::coro #endif // __WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED @@ -740,195 +718,197 @@ void __stdcall task_base::wake_by_address(void* completed) #if defined(_COMBASEAPI_H_) && defined(_THREADPOOLAPISET_H_) && !defined(__WIL_COROUTINE_NON_AGILE_INCLUDED) #define __WIL_COROUTINE_NON_AGILE_INCLUDED #include -#include #include +#include 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(restricted_error)); -} - -inline void __stdcall DestroyRestrictedErrorInformation(_In_ void* restricted_error) noexcept -{ - static_cast(restricted_error)->Release(); -} - -struct apartment_info -{ - APTTYPE aptType{}; - APTTYPEQUALIFIER aptTypeQualifier{}; - - void load() + inline void *__stdcall CaptureRestrictedErrorInformation() noexcept { - if (FAILED(CoGetApartmentType(&aptType, &aptTypeQualifier))) + 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(restricted_error)); + } + + inline void __stdcall DestroyRestrictedErrorInformation(_In_ void *restricted_error) noexcept + { + static_cast(restricted_error)->Release(); + } + + struct apartment_info + { + APTTYPE aptType{}; + APTTYPEQUALIFIER aptTypeQualifier{}; + + void load() { - // If COM is not initialized, then act as if we are running - // on the implicit MTA. - aptType = APTTYPE_MTA; - aptTypeQualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; + 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) + // apartment_resumer resumes a coroutine in a captured apartment. + struct apartment_resumer { - return reinterpret_cast(p); - } - - static bool is_sta() - { - apartment_info info; - info.load(); - switch (info.aptType) + static auto as_self(void *p) { - 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; + return reinterpret_cast(p); } - } - static wil::com_ptr current_context() - { - wil::com_ptr 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(&context)); - return context; - } - - __WI_COROUTINE_NAMESPACE::coroutine_handle<> waiter; - wil::com_ptr 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) + static bool is_sta() { - __debugbreak(); + 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 void __stdcall resume_in_context(void* parameter) - { - auto self = as_self(parameter); - if (self->context == nullptr || self->context == current_context()) + static wil::com_ptr current_context() { - self->context = nullptr; // removes the context cleanup from the resume path - self->waiter(); + wil::com_ptr 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(&context)); + return context; } - else if (is_sta()) + + __WI_COROUTINE_NAMESPACE::coroutine_handle<> waiter; + wil::com_ptr context{nullptr}; + apartment_info info{}; + HRESULT resume_result = S_OK; + + void capture_context(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle) { - submit_threadpool_callback(resume_context, self); + waiter = handle; + info.load(); + context = current_context(); + if (context == nullptr) + { + __debugbreak(); + } } - else + + static void __stdcall resume_in_context(void *parameter) { - self->resume_context_sync(); + 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)) + static void submit_threadpool_callback(PTP_SIMPLE_CALLBACK callback, void *context) { - // Unable to resume on the correct apartment. - // Resume on the wrong apartment, but tell the coroutine why. - resume_result = result; - waiter(); + THROW_IF_WIN32_BOOL_FALSE(TrySubmitThreadpoolCallback(callback, context, nullptr)); } - } - static HRESULT CALLBACK resume_apartment_callback(ComCallData* data) noexcept + 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 struct com_awaiter : agile_awaiter { - as_self(data->pUserDefined)->waiter(); - return S_OK; - } + com_awaiter(promise_ptr &&initial) : agile_awaiter(wistd::move(initial)) + { + } + apartment_resumer resumer; - void check() + 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::await_resume(); + } + }; + + template auto task_base::resume_same_apartment() && noexcept { - THROW_IF_FAILED(resume_result); + return com_awaiter{wistd::move(promise)}; } -}; - -// 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 -struct com_awaiter : agile_awaiter -{ - com_awaiter(promise_ptr&& initial) : agile_awaiter(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::await_resume(); - } -}; - -template -auto task_base::resume_same_apartment() && noexcept -{ - return com_awaiter{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; + ::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; }) diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt.h index 43570d7..7331c69 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt.h @@ -14,10 +14,10 @@ #define __WIL_CPPWINRT_INCLUDED #include "common.h" -#include -#include -#include #include +#include +#include +#include // 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 @@ -29,44 +29,44 @@ /// @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')) + // Since the C++/WinRT version macro is a string... + // For example: "2.0.221104.6" + inline constexpr int version_from_string(const char *versionString) { - 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 == '.') + int result = 0; + while ((*versionString >= '0') && (*versionString <= '9')) { - ++dotCount; + result = result * 10 + (*versionString - '0'); + ++versionString; } - ++versionString; - if (dotCount == 2) - { - return version_from_string(versionString); - } + return result; } - return 0; -} + 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 @@ -74,7 +74,8 @@ inline constexpr int minor_version_from_string(const char* versionString) // 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"); +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 @@ -82,10 +83,10 @@ static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, #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(); \ +#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 @@ -94,406 +95,408 @@ static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, #include #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"); +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; +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; +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) + inline void MaybeGetExceptionString(const winrt::hresult_error &exception, + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) + size_t debugStringChars) { - StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str()); + 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) + 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 { - try + if (g_pfnResultFromCaughtException) { - 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)) + try { - return hr; + 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 + else { - throw; + 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 + } } - 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; -} + // 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( - details::ReportFailure_CaughtException(__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(__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) + inline std::int32_t __stdcall winrt_to_hresult(void *returnAddress) noexcept { - WI_ASSERT(winrt_to_hresult_handler == nullptr); - winrt_to_hresult_handler = winrt_to_hresult; + // 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(details::ReportFailure_CaughtException( + __R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress))); + } - if constexpr (details::minor_version_from_string(CPPWINRT_VERSION) >= 210122) + 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(__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_throw_hresult_handler == nullptr); - winrt_throw_hresult_handler = winrt_throw_hresult; + 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 -{ + /// @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; - }); + 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") + WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1") #endif -} // namespace details -/// @endcond + } // 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 -auto get_abi(T const& object) noexcept -{ - return winrt::get_abi(object); -} - -inline auto get_abi(winrt::hstring const& object) noexcept -{ - return static_cast(winrt::get_abi(object)); -} - -inline auto str_raw_ptr(const winrt::hstring& str) noexcept -{ - return str.c_str(); -} - -template -auto put_abi(T& object) noexcept -{ - return winrt::put_abi(object); -} - -inline auto put_abi(winrt::hstring& object) noexcept -{ - return reinterpret_cast(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 -T convert_from_abi(::IUnknown* from) -{ - T to{nullptr}; // `T` is a projected type. - winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); - return to; -} - -// For obtaining an object from an interop method on the factory. Example: -// winrt::InputPane inputPane = wil::capture_interop(&IInputPaneInterop::GetForWindow, hwnd); -// If the method produces something different from the factory type: -// winrt::IAsyncAction action = wil::capture_interop(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd); -template -auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args) -{ - auto interop = winrt::get_activation_factory(); - return winrt::capture(interop, method, std::forward(args)...); -} - -// For obtaining an object from an interop method on an instance. Example: -// winrt::UserActivitySession session = wil::capture_interop(activity, &IUserActivityInterop::CreateSessionForWindow, hwnd); -template -auto capture_interop(winrt::Windows::Foundation::IUnknown const& o, HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args) -{ - return winrt::capture(o.as(), method, std::forward(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(); -@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(); -@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() + // 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 { - ++winrt::get_module_lock(); + return hr; } - winrt_module_reference(winrt_module_reference const&) : winrt_module_reference() + // Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience. + template auto get_abi(T const &object) noexcept { + return winrt::get_abi(object); } - ~winrt_module_reference() + inline auto get_abi(winrt::hstring const &object) noexcept { - --winrt::get_module_lock(); + return static_cast(winrt::get_abi(object)); } -}; -/** 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, - 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, -Version2_or_greater, IMyThing2, Version3, IMyThing3> -{ - // implementation goes here -}; -@endcode -*/ -template -struct winrt_conditionally_implements : Implements -{ - using Implements::Implements; - - void* find_interface(winrt::guid const& iid) const noexcept override + inline auto str_raw_ptr(const winrt::hstring &str) noexcept { - static_assert(sizeof...(Rest) % 2 == 0, "Extra template parameters should come in groups of two"); - if (is_enabled<0, std::tuple>(iid)) + return str.c_str(); + } + + template auto put_abi(T &object) noexcept + { + return winrt::put_abi(object); + } + + inline auto put_abi(winrt::hstring &object) noexcept + { + return reinterpret_cast(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 T convert_from_abi(::IUnknown *from) + { + T to{nullptr}; // `T` is a projected type. + winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); + return to; + } + + // For obtaining an object from an interop method on the factory. Example: + // winrt::InputPane inputPane = wil::capture_interop(&IInputPaneInterop::GetForWindow, hwnd); + // If the method produces something different from the factory type: + // winrt::IAsyncAction action = wil::capture_interop(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd); + template + auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args &&...args) + { + auto interop = winrt::get_activation_factory(); + return winrt::capture(interop, method, std::forward(args)...); + } + + // For obtaining an object from an interop method on an instance. Example: + // winrt::UserActivitySession session = wil::capture_interop(activity, + // &IUserActivityInterop::CreateSessionForWindow, hwnd); + template + auto capture_interop(winrt::Windows::Foundation::IUnknown const &o, + HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args &&...args) + { + return winrt::capture(o.as(), method, std::forward(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(); + @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(); + @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() { - return Implements::find_interface(iid); + ++winrt::get_module_lock(); } - return nullptr; - } -private: - template - static bool is_enabled(winrt::guid const& iid) - { - if constexpr (index >= std::tuple_size_v) + winrt_module_reference(winrt_module_reference const &) : winrt_module_reference() { - return true; } - else - { - check_no_duplicates<1, index + 1, Tuple>(); - return (iid == winrt::guid_of>()) ? std::tuple_element_t::IsEnabled() - : is_enabled(iid); - } - } - template - static constexpr void check_no_duplicates() - { - if constexpr (index < upto) + ~winrt_module_reference() { - static_assert( - !std::is_same_v, std::tuple_element_t>, - "Duplicate interfaces found in winrt_conditionally_implements"); - check_no_duplicates(); + --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, + 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, + Version2_or_greater, IMyThing2, Version3, IMyThing3> + { + // implementation goes here + }; + @endcode + */ + template 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>(iid)) + { + return Implements::find_interface(iid); + } + return nullptr; + } + + private: + template static bool is_enabled(winrt::guid const &iid) + { + if constexpr (index >= std::tuple_size_v) + { + return true; + } + else + { + check_no_duplicates<1, index + 1, Tuple>(); + return (iid == winrt::guid_of>()) + ? std::tuple_element_t::IsEnabled() + : is_enabled(iid); + } + } + + template static constexpr void check_no_duplicates() + { + if constexpr (index < upto) + { + static_assert(!std::is_same_v, std::tuple_element_t>, + "Duplicate interfaces found in winrt_conditionally_implements"); + check_no_duplicates(); + } + } + }; } // namespace wil #endif // __WIL_CPPWINRT_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_authoring.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_authoring.h index 9981968..3306165 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_authoring.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_authoring.h @@ -16,312 +16,305 @@ namespace wil #ifndef __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED /// @cond #define __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED -namespace details -{ - template - struct single_threaded_property_storage + namespace details { - T m_value{}; - single_threaded_property_storage() = default; - single_threaded_property_storage(const T& value) : m_value(value) + template 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 auto operator=(Q &&q) + { + m_value = wistd::forward(q); + return *this; + } + }; + } // namespace details + /// @endcond + + template + struct single_threaded_property : std::conditional_t || std::is_final_v, + wil::details::single_threaded_property_storage, T> + { + single_threaded_property() = default; + template + single_threaded_property(TArgs &&...value) : base_type(std::forward(value)...) { } - operator T&() + + using base_type = std::conditional_t || std::is_final_v, + wil::details::single_threaded_property_storage, T>; + + T operator()() const { - return m_value; + return *this; } - operator T const&() const + + // 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 instead. + template auto &operator=(Q &&q) { - return m_value; - } - template - auto operator=(Q&& q) - { - m_value = wistd::forward(q); + static_cast(*this) = std::forward(q); return *this; } }; -} // namespace details -/// @endcond -template -struct single_threaded_property - : std::conditional_t || std::is_final_v, wil::details::single_threaded_property_storage, T> -{ - single_threaded_property() = default; - template - single_threaded_property(TArgs&&... value) : base_type(std::forward(value)...) + template struct single_threaded_rw_property : single_threaded_property { - } + using base_type = single_threaded_property; + template + single_threaded_rw_property(TArgs &&...value) : base_type(std::forward(value)...) + { + } - using base_type = - std::conditional_t || std::is_final_v, wil::details::single_threaded_property_storage, T>; + using base_type::operator(); - T operator()() const - { - return *this; - } + // needed in lieu of deducing-this + template auto &operator()(Q &&q) + { + return *this = std::forward(q); + } - // 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 instead. - template - auto& operator=(Q&& q) - { - static_cast(*this) = std::forward(q); - return *this; - } -}; - -template -struct single_threaded_rw_property : single_threaded_property -{ - using base_type = single_threaded_property; - template - single_threaded_rw_property(TArgs&&... value) : base_type(std::forward(value)...) - { - } - - using base_type::operator(); - - // needed in lieu of deducing-this - template - auto& operator()(Q&& q) - { - return *this = std::forward(q); - } - - // needed in lieu of deducing-this - template - auto& operator=(Q&& q) - { - base_type::operator=(std::forward(q)); - return *this; - } -}; + // needed in lieu of deducing-this + template auto &operator=(Q &&q) + { + base_type::operator=(std::forward(q)); + return *this; + } + }; #endif // __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED -#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)) || \ +#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 - struct event_base + namespace details { - winrt::event_token operator()(const T& handler) + template struct event_base { - return m_handler.add(handler); - } + 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); - } + auto operator()(const winrt::event_token &token) noexcept + { + return m_handler.remove(token); + } - template - auto invoke(TArgs&&... args) - { - return m_handler(std::forward(args)...); - } + template auto invoke(TArgs &&...args) + { + return m_handler(std::forward(args)...); + } - private: - winrt::event m_handler; + private: + winrt::event 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 struct untyped_event : wil::details::event_base> + { }; -} // 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 -struct untyped_event : wil::details::event_base> -{ -}; - -/** - * @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 OkClicked; - * wil::typed_event OkClicked; - * @endcode - */ -template -struct typed_event : wil::details::event_base> -{ -}; + /** + * @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 OkClicked; + * wil::typed_event OkClicked; + * @endcode + */ + template + struct typed_event : wil::details::event_base> + { + }; #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))) || \ +#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 -{ + 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; + 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; + 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, wil::notify_property_changed_base - * { - * wil::single_threaded_notifying_property MyInt; - * MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { } - * // or - * WIL_NOTIFYING_PROPERTY(int, MyInt, 42); - * }; - * @endcode - */ -template -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(this); - } + } // namespace details + /// @endcond /** - * @brief Raises a property change notification event - * @param name The name of the property - * @return - * @details Usage example\n - * C++ + * @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 - * void MyPage::DoSomething() + * struct MyPage : MyPageT, wil::notify_property_changed_base * { - * // modify MyInt - * // MyInt = ... - * - * // now send a notification to update the bound UI elements - * RaisePropertyChanged(L"MyInt"); - * } + * wil::single_threaded_notifying_property MyInt; + * MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { } + * // or + * WIL_NOTIFYING_PROPERTY(int, MyInt, 42); + * }; * @endcode */ - auto RaisePropertyChanged(std::wstring_view name) + template + struct notify_property_changed_base { - return m_propertyChanged(self(), Xaml_Data_PropertyChangedEventArgs{name}); - } - -protected: - winrt::event 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 -struct single_threaded_notifying_property : single_threaded_rw_property -{ - using Type = T; - using base_type = single_threaded_rw_property; - using base_type::operator(); - - template - auto& operator()(Q&& q) - { - return *this = std::forward(q); - } - - template - auto& operator=(Q&& q) - { - if (q != this->operator()()) + using Type = T; + auto PropertyChanged(Xaml_Data_PropertyChangedEventHandler const &value) { - static_cast(*this) = std::forward(q); - if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr)) - { - (*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{m_name}); - } + return m_propertyChanged.add(value); } - return *this; - } - template - single_threaded_notifying_property( - winrt::event* npc, - const winrt::Windows::Foundation::IInspectable& sender, - std::wstring_view name, - TArgs&&... args) : - single_threaded_rw_property(std::forward(args)...), m_name(name), m_npc(npc), m_sender(sender) + void PropertyChanged(winrt::event_token const &token) + { + m_propertyChanged.remove(token); + } + + Type &self() + { + return *static_cast(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 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 + struct single_threaded_notifying_property : single_threaded_rw_property { - } + using Type = T; + using base_type = single_threaded_rw_property; + using base_type::operator(); - 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; - } + template auto &operator()(Q &&q) + { + return *this = std::forward(q); + } -private: - std::wstring_view m_name; - winrt::event* m_npc; - winrt::weak_ref m_sender; -}; + template auto &operator=(Q &&q) + { + if (q != this->operator()()) + { + static_cast(*this) = std::forward(q); + if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr)) + { + (*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{m_name}); + } + } + return *this; + } + + template + single_threaded_notifying_property(winrt::event *npc, + const winrt::Windows::Foundation::IInspectable &sender, + std::wstring_view name, TArgs &&...args) + : single_threaded_rw_property(std::forward(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 *m_npc; + winrt::weak_ref 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. + * @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. * @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; \ +#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; \ } /** @@ -330,5 +323,6 @@ private: */ #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)) +#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || + // defined(WINRT_Windows_UI_Xaml_Data_H)) } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_helpers.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_helpers.h index 6fdb140..38218fb 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_helpers.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_helpers.h @@ -17,152 +17,151 @@ /// @cond namespace wil::details { -struct dispatcher_RunAsync -{ - template - static void Schedule(Dispatcher const& dispatcher, Args&&... args) + struct dispatcher_RunAsync { - dispatcher.RunAsync(std::forward(args)...); - } -}; + template + static void Schedule(Dispatcher const &dispatcher, Args &&...args) + { + dispatcher.RunAsync(std::forward(args)...); + } + }; -struct dispatcher_TryEnqueue -{ - template - static void Schedule(Dispatcher const& dispatcher, Args&&... args) + struct dispatcher_TryEnqueue { - dispatcher.TryEnqueue(std::forward(args)...); - } -}; + template + static void Schedule(Dispatcher const &dispatcher, Args &&...args) + { + dispatcher.TryEnqueue(std::forward(args)...); + } + }; -template -struct dispatcher_traits; + template struct dispatcher_traits; } // namespace wil::details #if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) #include namespace wil::details { -template -using coroutine_handle = std::experimental::coroutine_handle; + template using coroutine_handle = std::experimental::coroutine_handle; } #elif defined(__cpp_impl_coroutine) #include #if (__cpp_lib_coroutine >= 201902L) namespace wil::details { -template -using coroutine_handle = std::coroutine_handle; + template using coroutine_handle = std::coroutine_handle; } #endif // __cpp_lib_coroutine #endif // __cpp_impl_coroutine /// @endcond -#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || \ +#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 dispatched_handler_state + { + details::coroutine_handle<> handle{}; + bool orphaned = false; + }; -struct dispatcher_handler -{ - dispatcher_handler(dispatched_handler_state* state) : m_state(state) + struct dispatcher_handler { - } - dispatcher_handler(dispatcher_handler&& other) noexcept : m_state(std::exchange(other.m_state, {})) - { - } - - ~dispatcher_handler() - { - if (m_state && m_state->handle) + 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()() { - m_state->orphaned = true; Complete(); } - } - void operator()() - { - Complete(); - } - void Complete() - { - auto state = std::exchange(m_state, nullptr); - std::exchange(state->handle, {}).resume(); - } + void Complete() + { + auto state = std::exchange(m_state, nullptr); + std::exchange(state->handle, {}).resume(); + } - dispatched_handler_state* m_state; -}; + 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 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 -[[nodiscard]] auto resume_foreground( - Dispatcher const& dispatcher, - typename details::dispatcher_traits::Priority priority = details::dispatcher_traits::Priority::Normal) -{ - using Traits = details::dispatcher_traits; - using Priority = typename Traits::Priority; - using Handler = typename Traits::Handler; - - struct awaitable + //! 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 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 + [[nodiscard]] auto resume_foreground(Dispatcher const &dispatcher, + typename details::dispatcher_traits::Priority priority = + details::dispatcher_traits::Priority::Normal) { - awaitable(Dispatcher const& dispatcher, Priority priority) noexcept : m_dispatcher(dispatcher), m_priority(priority) - { - } - bool await_ready() const noexcept - { - return false; - } + using Traits = details::dispatcher_traits; + using Priority = typename Traits::Priority; + using Handler = typename Traits::Handler; - void await_suspend(details::coroutine_handle<> handle) + struct awaitable { - m_state.handle = handle; - Handler handler{details::dispatcher_handler(&m_state)}; - try + awaitable(Dispatcher const &dispatcher, Priority priority) noexcept + : m_dispatcher(dispatcher), m_priority(priority) { - // 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 (...) + bool await_ready() const noexcept { - m_state.handle = nullptr; // the exception will resume the coroutine, so the handler shouldn't do it - throw; + return false; } - } - void await_resume() const - { - if (m_state.orphaned) + void await_suspend(details::coroutine_handle<> handle) { - throw winrt::hresult_error(static_cast(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE) + 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; + } } - } - private: - Dispatcher const& m_dispatcher; - Priority const m_priority; - details::dispatched_handler_state m_state; - }; - return awaitable{dispatcher, priority}; -} + void await_resume() const + { + if (m_state.orphaned) + { + throw winrt::hresult_error( + static_cast(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 @@ -173,13 +172,12 @@ template #define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS namespace wil::details { -template <> -struct dispatcher_traits -{ - using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority; - using Handler = winrt::Windows::UI::Core::DispatchedHandler; - using Scheduler = dispatcher_RunAsync; -}; + template <> struct dispatcher_traits + { + 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 @@ -187,13 +185,12 @@ struct dispatcher_traits #define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS namespace wil::details { -template <> -struct dispatcher_traits -{ - using Priority = winrt::Windows::System::DispatcherQueuePriority; - using Handler = winrt::Windows::System::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; -}; + template <> struct dispatcher_traits + { + 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 @@ -201,13 +198,12 @@ struct dispatcher_traits #define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS namespace wil::details { -template <> -struct dispatcher_traits -{ - using Priority = winrt::Microsoft::System::DispatcherQueuePriority; - using Handler = winrt::Microsoft::System::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; -}; + template <> struct dispatcher_traits + { + 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 @@ -215,144 +211,140 @@ struct dispatcher_traits #define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS namespace wil::details { -template <> -struct dispatcher_traits -{ - using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority; - using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; -}; + template <> struct dispatcher_traits + { + 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)) || \ +#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 - struct is_winrt_vector_like + /// @cond + namespace details { - private: - template < - typename U, - typename = decltype(std::declval().GetMany(std::declval().Size(), winrt::array_view().GetAt(0))>{}))> - static constexpr bool get_value(int) + template struct is_winrt_vector_like { - return true; - } - template - static constexpr bool get_value(...) + private: + template ().GetMany( + std::declval().Size(), winrt::array_view().GetAt(0))>{}))> + static constexpr bool get_value(int) + { + return true; + } + template static constexpr bool get_value(...) + { + return false; + } + + public: + static constexpr bool value = get_value(0); + }; + + template struct is_winrt_iterator_like { - return false; + private: + template ().GetMany( + winrt::array_view().Current())>{}))> + static constexpr bool get_value(int) + { + return true; + } + template static constexpr bool get_value(...) + { + return false; + } + + public: + static constexpr bool value = get_value(0); + }; + + template constexpr T empty() noexcept + { + if constexpr (std::is_base_of_v) + { + return nullptr; + } + else + { + return {}; + } } + } // namespace details + /// @endcond - public: - static constexpr bool value = get_value(0); - }; - - template - struct is_winrt_iterator_like + /** 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 collection = GetCollection(); + std::vector allData = wil::to_vector(collection); // read all data from collection + for (winrt::hstring const& item : allData) { - private: - template ().GetMany(winrt::array_view().Current())>{}))> - static constexpr bool get_value(int) - { - return true; - } - template - static constexpr bool get_value(...) - { - return false; - } - - public: - static constexpr bool value = get_value(0); - }; - - template - constexpr T empty() noexcept + // use item + } + @endcode + Can be used for IVector, IVectorView, IIterable, IIterator, and any type or + interface that C++/WinRT projects those interfaces for (PropertySet, IMap, 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 auto to_vector(TSrc const &src) { - if constexpr (std::is_base_of_v) + if constexpr (details::is_winrt_vector_like::value) { - return nullptr; + using T = decltype(src.GetAt(0)); + std::vector result; + if (auto expected = src.Size()) + { + result.resize(expected + 1, details::empty()); + auto actual = src.GetMany(0, result); + if (actual > expected) + { + throw winrt::hresult_changed_state(); + } + result.resize(actual, details::empty()); + } + return result; + } + else if constexpr (details::is_winrt_iterator_like::value) + { + using T = decltype(src.Current()); + std::vector result; + constexpr uint32_t chunkSize = 64; + while (true) + { + auto const lastSize = result.size(); + result.resize(lastSize + chunkSize, details::empty()); + auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize}); + if (fetched < chunkSize) + { + result.resize(lastSize + fetched, details::empty()); + break; + } + } + return result; } else { - return {}; + return to_vector(src.First()); } } -} // 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 collection = GetCollection(); -std::vector allData = wil::to_vector(collection); // read all data from collection -for (winrt::hstring const& item : allData) -{ - // use item -} -@endcode -Can be used for IVector, IVectorView, IIterable, IIterator, and any type or -interface that C++/WinRT projects those interfaces for (PropertySet, IMap, 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 -auto to_vector(TSrc const& src) -{ - if constexpr (details::is_winrt_vector_like::value) - { - using T = decltype(src.GetAt(0)); - std::vector result; - if (auto expected = src.Size()) - { - result.resize(expected + 1, details::empty()); - auto actual = src.GetMany(0, result); - if (actual > expected) - { - throw winrt::hresult_changed_state(); - } - result.resize(actual, details::empty()); - } - return result; - } - else if constexpr (details::is_winrt_iterator_like::value) - { - using T = decltype(src.Current()); - std::vector result; - constexpr uint32_t chunkSize = 64; - while (true) - { - auto const lastSize = result.size(); - result.resize(lastSize + chunkSize, details::empty()); - auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize}); - if (fetched < chunkSize) - { - result.resize(lastSize + fetched, details::empty()); - 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)) || \ +#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 @@ -366,24 +358,24 @@ auto to_vector(TSrc const& src) namespace wil { #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU) -//! The following methods require that you include both -//! 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}; -} + //! The following methods require that you include both + //! 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; -} + 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 diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_notifiable_module_lock.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_notifiable_module_lock.h index 5aa9260..7b2ca07 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_notifiable_module_lock.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_notifiable_module_lock.h @@ -27,84 +27,83 @@ 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) + // Adopted from cppwinrt + struct notifiable_module_lock_base { - } + notifiable_module_lock_base() = default; - 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) + notifiable_module_lock_base(uint32_t count) : m_count(count) { - std::atomic_thread_fence(std::memory_order_acquire); - if (notifier) // Protect against callback not being set yet + } + + 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) { - notifier(); + 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; } - else if (remaining < 0) + + operator uint32_t() const noexcept { - abort(); + return m_count; } - return remaining; - } + template void set_notifier(Func &&func) + { + notifier = std::forward(func); + } - operator uint32_t() const noexcept + void set_notifier(std::nullptr_t) noexcept + { + notifier = nullptr; + } + + private: + std::atomic m_count{0}; + std::function notifier{}; + }; + + struct notifiable_module_lock final : notifiable_module_lock_base { - return m_count; - } - - template - void set_notifier(Func&& func) - { - notifier = std::forward(func); - } - - void set_notifier(std::nullptr_t) noexcept - { - notifier = nullptr; - } - -private: - std::atomic m_count{0}; - std::function notifier{}; -}; - -struct notifiable_module_lock final : notifiable_module_lock_base -{ - static notifiable_module_lock& instance() noexcept - { - static notifiable_module_lock lock; - return lock; - } -}; + 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(); -} + auto &get_module_lock() + { + return wil::notifiable_module_lock::instance(); + } } // namespace winrt #endif diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_register_com_server.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_register_com_server.h index 87593eb..521c579 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_register_com_server.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_register_com_server.h @@ -14,63 +14,62 @@ #ifndef __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED #define __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED -#include -#include -#include #include +#include +#include +#include namespace wil::details { -template -struct CppWinRTClassFactory : winrt::implements, IClassFactory, winrt::no_module_lock> -{ - HRESULT __stdcall CreateInstance(IUnknown* outer, GUID const& iid, void** result) noexcept final - try + template + struct CppWinRTClassFactory : winrt::implements, IClassFactory, winrt::no_module_lock> { - *result = nullptr; - - if (outer) + HRESULT __stdcall CreateInstance(IUnknown *outer, GUID const &iid, void **result) noexcept final + try { - return CLASS_E_NOAGGREGATION; + *result = nullptr; + + if (outer) + { + return CLASS_E_NOAGGREGATION; + } + return winrt::make_self().as(iid, result); } - return winrt::make_self().as(iid, result); - } - CATCH_RETURN() + CATCH_RETURN() - HRESULT __stdcall LockServer(BOOL) noexcept final + HRESULT __stdcall LockServer(BOOL) noexcept final + { + return S_OK; + } + }; + + template + void register_com_server(std::vector ®istrations) { - return S_OK; + DWORD registration{}; + winrt::check_hresult(CoRegisterClassObject(winrt::guid_of(), winrt::make>().get(), + CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®istration)); + // This emplace_back is no-throw as wil::register_com_server already reserves enough capacity + registrations.emplace_back(registration); + register_com_server(registrations); } -}; -template -void register_com_server(std::vector& registrations) -{ - DWORD registration{}; - winrt::check_hresult(CoRegisterClassObject( - winrt::guid_of(), winrt::make>().get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®istration)); - // This emplace_back is no-throw as wil::register_com_server already reserves enough capacity - registrations.emplace_back(registration); - register_com_server(registrations); -} - -template <> -void register_com_server(std::vector&) -{ -} + template <> void register_com_server(std::vector &) + { + } } // namespace wil::details namespace wil { -template -[[nodiscard]] std::vector register_com_server() -{ - std::vector registrations; - registrations.reserve(sizeof...(Rest) + 1); - details::register_com_server(registrations); - // C++17 doesn't provide guaranteed copy elision, but the copy should be elided nonetheless. - return registrations; -} + template + [[nodiscard]] std::vector register_com_server() + { + std::vector registrations; + registrations.reserve(sizeof...(Rest) + 1); + details::register_com_server(registrations); + // C++17 doesn't provide guaranteed copy elision, but the copy should be elided nonetheless. + return registrations; + } } // namespace wil #endif \ No newline at end of file diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_wrl.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_wrl.h index 43d13b3..05f0a88 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_wrl.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/cppwinrt_wrl.h @@ -32,49 +32,48 @@ // namespace wil { -/// @cond -namespace details -{ - template - class module_count_wrapper : public TCppWinRTClass + /// @cond + namespace details { - public: - module_count_wrapper() + template class module_count_wrapper : public TCppWinRTClass { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + public: + module_count_wrapper() { - modulePtr->IncrementObjectCount(); + if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + { + modulePtr->IncrementObjectCount(); + } } - } - virtual ~module_count_wrapper() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + virtual ~module_count_wrapper() { - modulePtr->DecrementObjectCount(); + if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + { + modulePtr->DecrementObjectCount(); + } } + }; + } // namespace details + /// @endcond + + template 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>().as(riid, object); } + CATCH_RETURN() }; -} // namespace details -/// @endcond - -template -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>().as(riid, object); - } - CATCH_RETURN() -}; } // namespace wil -#define CoCreatableCppWinRtClass(className) \ +#define CoCreatableCppWinRtClass(className) \ CoCreatableClassWithFactory(className, ::wil::wrl_factory_for_winrt_com_class) #endif // __WIL_CPPWINRT_WRL_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/filesystem.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/filesystem.h index f4a801c..da645fb 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/filesystem.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/filesystem.h @@ -17,14 +17,14 @@ #error This header is not supported in kernel-mode. #endif -#include -#include // Needed for CoTaskMemFree() used in output of some helpers. -#include // LocalAlloc -#include -#include "wistd_type_traits.h" +#include "resource.h" #include "result.h" #include "win32_helpers.h" -#include "resource.h" +#include "wistd_type_traits.h" +#include +#include // Needed for CoTaskMemFree() used in output of some helpers. +#include +#include // LocalAlloc #if WIL_USE_STL #include @@ -32,1299 +32,1328 @@ namespace wil { -//! Determines if a path is an extended length path that can be used to access paths longer than MAX_PATH. -inline bool is_extended_length_path(_In_ PCWSTR path) -{ - return wcsncmp(path, L"\\\\?\\", 4) == 0; -} + //! Determines if a path is an extended length path that can be used to access paths longer than MAX_PATH. + inline bool is_extended_length_path(_In_ PCWSTR path) + { + return wcsncmp(path, L"\\\\?\\", 4) == 0; + } #if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) -//! Find the last segment of a path. Matches the behavior of shlwapi!PathFindFileNameW() -//! note, does not support streams being specified like PathFindFileNameW(), is that a bug or a feature? -inline PCWSTR find_last_path_segment(_In_ PCWSTR path) -{ - auto const pathLength = wcslen(path); - // If there is a trailing slash ignore that in the search. - auto const limitedLength = ((pathLength > 0) && (path[pathLength - 1] == L'\\')) ? (pathLength - 1) : pathLength; + //! Find the last segment of a path. Matches the behavior of shlwapi!PathFindFileNameW() + //! note, does not support streams being specified like PathFindFileNameW(), is that a bug or a feature? + inline PCWSTR find_last_path_segment(_In_ PCWSTR path) + { + auto const pathLength = wcslen(path); + // If there is a trailing slash ignore that in the search. + auto const limitedLength = + ((pathLength > 0) && (path[pathLength - 1] == L'\\')) ? (pathLength - 1) : pathLength; - PCWSTR result = nullptr; - auto const offset = FindStringOrdinal(FIND_FROMEND, path, static_cast(limitedLength), L"\\", 1, TRUE); - if (offset == -1) - { - result = path + pathLength; // null terminator - } - else - { - result = path + offset + 1; // just past the slash - } - return result; -} -#endif - -//! Determine if the file name is one of the special "." or ".." names. -inline bool path_is_dot_or_dotdot(_In_ PCWSTR fileName) -{ - return ((fileName[0] == L'.') && ((fileName[1] == L'\0') || ((fileName[1] == L'.') && (fileName[2] == L'\0')))); -} - -//! Returns the drive number, if it has one. Returns true if there is a drive number, false otherwise. Supports regular and -//! extended length paths. -inline bool try_get_drive_letter_number(_In_ PCWSTR path, _Out_ int* driveNumber) -{ - if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'?' && path[3] == L'\\') - { - path += 4; - } - if (path[0] && (path[1] == L':')) - { - if ((path[0] >= L'a') && (path[0] <= L'z')) + PCWSTR result = nullptr; + auto const offset = FindStringOrdinal(FIND_FROMEND, path, static_cast(limitedLength), L"\\", 1, TRUE); + if (offset == -1) { - *driveNumber = path[0] - L'a'; - return true; - } - else if ((path[0] >= L'A') && (path[0] <= L'Z')) - { - *driveNumber = path[0] - L'A'; - return true; - } - } - *driveNumber = -1; - return false; -} - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) - -// PathCch.h APIs are only in desktop API for now. - -// Compute the substring in the input value that is the parent folder path. -// returns: -// true + parentPathLength - path has a parent starting at the beginning path and of parentPathLength length. -// false, no parent path, the input is a root path. -inline bool try_get_parent_path_range(_In_ PCWSTR path, _Out_ size_t* parentPathLength) -{ - *parentPathLength = 0; - bool hasParent = false; - PCWSTR rootEnd = nullptr; - if (SUCCEEDED(PathCchSkipRoot(path, &rootEnd)) && (*rootEnd != L'\0')) - { - auto const lastSegment = find_last_path_segment(path); - *parentPathLength = lastSegment - path; - hasParent = (*parentPathLength != 0); - } - return hasParent; -} - -// Creates directories for the specified path, creating parent paths -// as needed. -inline HRESULT CreateDirectoryDeepNoThrow(PCWSTR path) WI_NOEXCEPT -{ - if (::CreateDirectoryW(path, nullptr) == FALSE) - { - DWORD lastError = ::GetLastError(); - if (lastError == ERROR_PATH_NOT_FOUND) - { - size_t parentLength{}; - if (try_get_parent_path_range(path, &parentLength)) - { - wistd::unique_ptr parent(new (std::nothrow) wchar_t[parentLength + 1]); - RETURN_IF_NULL_ALLOC(parent.get()); - RETURN_IF_FAILED(StringCchCopyNW(parent.get(), parentLength + 1, path, parentLength)); - RETURN_IF_FAILED(CreateDirectoryDeepNoThrow(parent.get())); // recurs - } - if (::CreateDirectoryW(path, nullptr) == FALSE) - { - lastError = ::GetLastError(); - if (lastError != ERROR_ALREADY_EXISTS) - { - RETURN_WIN32(lastError); - } - } - } - else if (lastError != ERROR_ALREADY_EXISTS) - { - RETURN_WIN32(lastError); - } - } - return S_OK; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -inline void CreateDirectoryDeep(PCWSTR path) -{ - THROW_IF_FAILED(CreateDirectoryDeepNoThrow(path)); -} -#endif // WIL_ENABLE_EXCEPTIONS - -//! A strongly typed version of the Win32 API GetFullPathNameW. -//! Return a path in an allocated buffer for handling long paths. -//! Optionally return the pointer to the file name part. -template -HRESULT GetFullPathNameW(PCWSTR file, string_type& path, _Outptr_opt_ PCWSTR* filePart = nullptr) -{ - wil::assign_null_to_opt_param(filePart); - const auto hr = AdaptFixedSizeToAllocatedResult( - path, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT { - // Note that GetFullPathNameW() is not limited to MAX_PATH - // but it does take a fixed size buffer. - *valueLengthNeededWithNull = ::GetFullPathNameW(file, static_cast(valueLength), value, nullptr); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) - { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); - if (SUCCEEDED(hr) && filePart) - { - *filePart = wil::find_last_path_segment(details::string_maker::get(path)); - } - return hr; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! A strongly typed version of the Win32 API of GetFullPathNameW. -//! Return a path in an allocated buffer for handling long paths. -//! Optionally return the pointer to the file name part. -template -string_type GetFullPathNameW(PCWSTR file, _Outptr_opt_ PCWSTR* filePart = nullptr) -{ - string_type result{}; - THROW_IF_FAILED((GetFullPathNameW(file, result, filePart))); - return result; -} -#endif - -enum class RemoveDirectoryOptions -{ - None = 0, - KeepRootDirectory = 0x1, - RemoveReadOnly = 0x2, -}; -DEFINE_ENUM_FLAG_OPERATORS(RemoveDirectoryOptions); - -/// @cond -namespace details -{ - // Reparse points should not be traversed in most recursive walks of the file system, - // unless allowed through the appropriate reparse tag. - inline bool CanRecurseIntoDirectory(const FILE_ATTRIBUTE_TAG_INFO& info) - { - return ( - WI_IsFlagSet(info.FileAttributes, FILE_ATTRIBUTE_DIRECTORY) && - (WI_IsFlagClear(info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) || - (IsReparseTagDirectory(info.ReparseTag) || (info.ReparseTag == IO_REPARSE_TAG_WCI)))); - } -} // namespace details -/// @endcond - -// Retrieve a handle to a directory only if it is safe to recurse into. -inline wil::unique_hfile TryCreateFileCanRecurseIntoDirectory( - PCWSTR path, PWIN32_FIND_DATAW fileFindData, DWORD access = GENERIC_READ | /*DELETE*/ 0x00010000L, DWORD share = FILE_SHARE_READ) -{ - wil::unique_hfile result( - CreateFileW(path, access, share, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); - if (result) - { - FILE_ATTRIBUTE_TAG_INFO fati{}; - if (GetFileInformationByHandleEx(result.get(), FileAttributeTagInfo, &fati, sizeof(fati)) && - details::CanRecurseIntoDirectory(fati)) - { - if (fileFindData) - { - // Refresh the found file's data now that we have secured the directory from external manipulation. - fileFindData->dwFileAttributes = fati.FileAttributes; - fileFindData->dwReserved0 = fati.ReparseTag; - } + result = path + pathLength; // null terminator } else { - result.reset(); + result = path + offset + 1; // just past the slash } + return result; + } +#endif + + //! Determine if the file name is one of the special "." or ".." names. + inline bool path_is_dot_or_dotdot(_In_ PCWSTR fileName) + { + return ((fileName[0] == L'.') && ((fileName[1] == L'\0') || ((fileName[1] == L'.') && (fileName[2] == L'\0')))); } - return result; -} - -// If inputPath is a non-normalized name be sure to pass an extended length form to ensure -// it can be addressed and deleted. -inline HRESULT RemoveDirectoryRecursiveNoThrow( - PCWSTR inputPath, RemoveDirectoryOptions options = RemoveDirectoryOptions::None, HANDLE deleteHandle = INVALID_HANDLE_VALUE) WI_NOEXCEPT -{ - wil::unique_hlocal_string path; - PATHCCH_OPTIONS combineOptions = PATHCCH_NONE; - - if (is_extended_length_path(inputPath)) + //! Returns the drive number, if it has one. Returns true if there is a drive number, false otherwise. Supports + //! regular and extended length paths. + inline bool try_get_drive_letter_number(_In_ PCWSTR path, _Out_ int *driveNumber) { - path = wil::make_hlocal_string_nothrow(inputPath); - RETURN_IF_NULL_ALLOC(path); - // PathAllocCombine will convert extended length paths to regular paths if shorter than - // MAX_PATH, avoid that behavior to provide access inputPath with non-normalized names. - combineOptions = PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH; - } - else - { - // For regular paths normalize here to get consistent results when searching and deleting. - RETURN_IF_FAILED(wil::GetFullPathNameW(inputPath, path)); - combineOptions = PATHCCH_ALLOW_LONG_PATHS; - } - - wil::unique_hlocal_string searchPath; - RETURN_IF_FAILED(::PathAllocCombine(path.get(), L"*", combineOptions, &searchPath)); - - WIN32_FIND_DATAW fd{}; - wil::unique_hfind findHandle(::FindFirstFileW(searchPath.get(), &fd)); - RETURN_LAST_ERROR_IF(!findHandle); - - for (;;) - { - // skip "." and ".." - if (!(WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && path_is_dot_or_dotdot(fd.cFileName))) + if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'?' && path[3] == L'\\') { - // Need to form an extended length path to provide the ability to delete paths > MAX_PATH - // and files with non-normalized names (dots or spaces at the end). - wil::unique_hlocal_string pathToDelete; - RETURN_IF_FAILED(::PathAllocCombine( - path.get(), fd.cFileName, PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &pathToDelete)); - if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + path += 4; + } + if (path[0] && (path[1] == L':')) + { + if ((path[0] >= L'a') && (path[0] <= L'z')) { - // Get a handle to the directory to delete, preventing it from being replaced to prevent writes which could be - // used to bypass permission checks, and verify that it is not a name surrogate (e.g. symlink, mount point, etc). - wil::unique_hfile recursivelyDeletableDirectoryHandle = TryCreateFileCanRecurseIntoDirectory(pathToDelete.get(), &fd); - if (recursivelyDeletableDirectoryHandle) + *driveNumber = path[0] - L'a'; + return true; + } + else if ((path[0] >= L'A') && (path[0] <= L'Z')) + { + *driveNumber = path[0] - L'A'; + return true; + } + } + *driveNumber = -1; + return false; + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + + // PathCch.h APIs are only in desktop API for now. + + // Compute the substring in the input value that is the parent folder path. + // returns: + // true + parentPathLength - path has a parent starting at the beginning path and of parentPathLength length. + // false, no parent path, the input is a root path. + inline bool try_get_parent_path_range(_In_ PCWSTR path, _Out_ size_t *parentPathLength) + { + *parentPathLength = 0; + bool hasParent = false; + PCWSTR rootEnd = nullptr; + if (SUCCEEDED(PathCchSkipRoot(path, &rootEnd)) && (*rootEnd != L'\0')) + { + auto const lastSegment = find_last_path_segment(path); + *parentPathLength = lastSegment - path; + hasParent = (*parentPathLength != 0); + } + return hasParent; + } + + // Creates directories for the specified path, creating parent paths + // as needed. + inline HRESULT CreateDirectoryDeepNoThrow(PCWSTR path) WI_NOEXCEPT + { + if (::CreateDirectoryW(path, nullptr) == FALSE) + { + DWORD lastError = ::GetLastError(); + if (lastError == ERROR_PATH_NOT_FOUND) + { + size_t parentLength{}; + if (try_get_parent_path_range(path, &parentLength)) { - RemoveDirectoryOptions localOptions = options; - RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow( - pathToDelete.get(), - WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory), - recursivelyDeletableDirectoryHandle.get())); + wistd::unique_ptr parent(new (std::nothrow) wchar_t[parentLength + 1]); + RETURN_IF_NULL_ALLOC(parent.get()); + RETURN_IF_FAILED(StringCchCopyNW(parent.get(), parentLength + 1, path, parentLength)); + RETURN_IF_FAILED(CreateDirectoryDeepNoThrow(parent.get())); // recurs } - else if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + if (::CreateDirectoryW(path, nullptr) == FALSE) { - // This is a directory reparse point that should not be recursed. Delete it without traversing into it. - RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(pathToDelete.get())); + lastError = ::GetLastError(); + if (lastError != ERROR_ALREADY_EXISTS) + { + RETURN_WIN32(lastError); + } } - else + } + else if (lastError != ERROR_ALREADY_EXISTS) + { + RETURN_WIN32(lastError); + } + } + return S_OK; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline void CreateDirectoryDeep(PCWSTR path) + { + THROW_IF_FAILED(CreateDirectoryDeepNoThrow(path)); + } +#endif // WIL_ENABLE_EXCEPTIONS + + //! A strongly typed version of the Win32 API GetFullPathNameW. + //! Return a path in an allocated buffer for handling long paths. + //! Optionally return the pointer to the file name part. + template + HRESULT GetFullPathNameW(PCWSTR file, string_type &path, _Outptr_opt_ PCWSTR *filePart = nullptr) + { + wil::assign_null_to_opt_param(filePart); + const auto hr = AdaptFixedSizeToAllocatedResult( + path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNull) -> HRESULT { + // Note that GetFullPathNameW() is not limited to MAX_PATH + // but it does take a fixed size buffer. + *valueLengthNeededWithNull = ::GetFullPathNameW(file, static_cast(valueLength), value, nullptr); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) { - // Failed to grab a handle to the file or to read its attributes. This is not safe to recurse. - RETURN_WIN32(::GetLastError()); + (*valueLengthNeededWithNull)++; // it fit, account for the null + } + return S_OK; + }); + if (SUCCEEDED(hr) && filePart) + { + *filePart = wil::find_last_path_segment(details::string_maker::get(path)); + } + return hr; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! A strongly typed version of the Win32 API of GetFullPathNameW. + //! Return a path in an allocated buffer for handling long paths. + //! Optionally return the pointer to the file name part. + template + string_type GetFullPathNameW(PCWSTR file, _Outptr_opt_ PCWSTR *filePart = nullptr) + { + string_type result{}; + THROW_IF_FAILED((GetFullPathNameW(file, result, filePart))); + return result; + } +#endif + + enum class RemoveDirectoryOptions + { + None = 0, + KeepRootDirectory = 0x1, + RemoveReadOnly = 0x2, + }; + DEFINE_ENUM_FLAG_OPERATORS(RemoveDirectoryOptions); + + /// @cond + namespace details + { + // Reparse points should not be traversed in most recursive walks of the file system, + // unless allowed through the appropriate reparse tag. + inline bool CanRecurseIntoDirectory(const FILE_ATTRIBUTE_TAG_INFO &info) + { + return (WI_IsFlagSet(info.FileAttributes, FILE_ATTRIBUTE_DIRECTORY) && + (WI_IsFlagClear(info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) || + (IsReparseTagDirectory(info.ReparseTag) || (info.ReparseTag == IO_REPARSE_TAG_WCI)))); + } + } // namespace details + /// @endcond + + // Retrieve a handle to a directory only if it is safe to recurse into. + inline wil::unique_hfile TryCreateFileCanRecurseIntoDirectory(PCWSTR path, PWIN32_FIND_DATAW fileFindData, + DWORD access = GENERIC_READ | /*DELETE*/ 0x00010000L, + DWORD share = FILE_SHARE_READ) + { + wil::unique_hfile result(CreateFileW(path, access, share, nullptr, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); + if (result) + { + FILE_ATTRIBUTE_TAG_INFO fati{}; + if (GetFileInformationByHandleEx(result.get(), FileAttributeTagInfo, &fati, sizeof(fati)) && + details::CanRecurseIntoDirectory(fati)) + { + if (fileFindData) + { + // Refresh the found file's data now that we have secured the directory from external manipulation. + fileFindData->dwFileAttributes = fati.FileAttributes; + fileFindData->dwReserved0 = fati.ReparseTag; } } else { - // Try a DeleteFile. Some errors may be recoverable. - if (!::DeleteFileW(pathToDelete.get())) - { - // Fail for anything other than ERROR_ACCESS_DENIED with option to RemoveReadOnly available - bool potentiallyFixableReadOnlyProblem = - WI_IsFlagSet(options, RemoveDirectoryOptions::RemoveReadOnly) && ::GetLastError() == ERROR_ACCESS_DENIED; - RETURN_LAST_ERROR_IF(!potentiallyFixableReadOnlyProblem); - - // Fail if the file does not have read-only set, likely just an ACL problem - DWORD fileAttr = ::GetFileAttributesW(pathToDelete.get()); - RETURN_LAST_ERROR_IF(!WI_IsFlagSet(fileAttr, FILE_ATTRIBUTE_READONLY)); - - // Remove read-only flag, setting to NORMAL if completely empty - WI_ClearFlag(fileAttr, FILE_ATTRIBUTE_READONLY); - if (fileAttr == 0) - { - fileAttr = FILE_ATTRIBUTE_NORMAL; - } - - // Set the new attributes and try to delete the file again, returning any failure - ::SetFileAttributesW(pathToDelete.get(), fileAttr); - RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get())); - } + result.reset(); } } - if (!::FindNextFileW(findHandle.get(), &fd)) - { - auto const err = ::GetLastError(); - if (err == ERROR_NO_MORE_FILES) - { - break; - } - RETURN_WIN32(err); - } + return result; } - if (WI_IsFlagClear(options, RemoveDirectoryOptions::KeepRootDirectory)) + // If inputPath is a non-normalized name be sure to pass an extended length form to ensure + // it can be addressed and deleted. + inline HRESULT RemoveDirectoryRecursiveNoThrow(PCWSTR inputPath, + RemoveDirectoryOptions options = RemoveDirectoryOptions::None, + HANDLE deleteHandle = INVALID_HANDLE_VALUE) WI_NOEXCEPT { - if (deleteHandle != INVALID_HANDLE_VALUE) + wil::unique_hlocal_string path; + PATHCCH_OPTIONS combineOptions = PATHCCH_NONE; + + if (is_extended_length_path(inputPath)) { -#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) - // DeleteFile and RemoveDirectory use POSIX delete, falling back to non-POSIX on most errors. Do the same here. - FILE_DISPOSITION_INFO_EX fileInfoEx{}; - fileInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; - if (!SetFileInformationByHandle(deleteHandle, FileDispositionInfoEx, &fileInfoEx, sizeof(fileInfoEx))) - { - auto const err = ::GetLastError(); - // The real error we're looking for is STATUS_CANNOT_DELETE, but that's mapped to ERROR_ACCESS_DENIED. - if (err != ERROR_ACCESS_DENIED) - { -#endif - FILE_DISPOSITION_INFO fileInfo{}; - fileInfo.DeleteFile = TRUE; - RETURN_IF_WIN32_BOOL_FALSE(SetFileInformationByHandle(deleteHandle, FileDispositionInfo, &fileInfo, sizeof(fileInfo))); -#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) - } - else - { - RETURN_WIN32(err); - } - } -#endif + path = wil::make_hlocal_string_nothrow(inputPath); + RETURN_IF_NULL_ALLOC(path); + // PathAllocCombine will convert extended length paths to regular paths if shorter than + // MAX_PATH, avoid that behavior to provide access inputPath with non-normalized names. + combineOptions = PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH; } else { - RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get())); + // For regular paths normalize here to get consistent results when searching and deleting. + RETURN_IF_FAILED(wil::GetFullPathNameW(inputPath, path)); + combineOptions = PATHCCH_ALLOW_LONG_PATHS; } - } - return S_OK; -} -#ifdef WIL_ENABLE_EXCEPTIONS -inline void RemoveDirectoryRecursive(PCWSTR path, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) -{ - THROW_IF_FAILED(RemoveDirectoryRecursiveNoThrow(path, options)); -} -#endif // WIL_ENABLE_EXCEPTIONS + wil::unique_hlocal_string searchPath; + RETURN_IF_FAILED(::PathAllocCombine(path.get(), L"*", combineOptions, &searchPath)); -// Range based for that supports Win32 structures that use NextEntryOffset as the basis of traversing -// a result buffer that contains data. This is used in the following FileIO calls: -// FileStreamInfo, FILE_STREAM_INFO -// FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO -// FileFullDirectoryInfo, FILE_FULL_DIR_INFO -// FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO -// ReadDirectoryChangesW, FILE_NOTIFY_INFORMATION + WIN32_FIND_DATAW fd{}; + wil::unique_hfind findHandle(::FindFirstFileW(searchPath.get(), &fd)); + RETURN_LAST_ERROR_IF(!findHandle); -template -struct next_entry_offset_iterator -{ - // Fulfill std::iterator_traits requirements - using difference_type = ptrdiff_t; - using value_type = T; - using pointer = const T*; - using reference = const T&; -#if WIL_USE_STL - using iterator_category = ::std::forward_iterator_tag; -#endif - - next_entry_offset_iterator(T* iterable = __nullptr) : current_(iterable) - { - } - - // range based for requires operator!=, operator++ and operator* to do its work - // on the type returned from begin() and end(), provide those here. - WI_NODISCARD bool operator!=(const next_entry_offset_iterator& other) const - { - return current_ != other.current_; - } - - next_entry_offset_iterator& operator++() - { - current_ = (current_->NextEntryOffset != 0) - ? reinterpret_cast(reinterpret_cast(current_) + current_->NextEntryOffset) - : __nullptr; - return *this; - } - - next_entry_offset_iterator operator++(int) - { - auto copy = *this; - ++(*this); - return copy; - } - - WI_NODISCARD reference operator*() const WI_NOEXCEPT - { - return *current_; - } - WI_NODISCARD pointer operator->() const WI_NOEXCEPT - { - return current_; - } - - next_entry_offset_iterator begin() - { - return *this; - } - next_entry_offset_iterator end() - { - return next_entry_offset_iterator(); - } - - T* current_; -}; - -template -next_entry_offset_iterator create_next_entry_offset_iterator(T* p) -{ - return next_entry_offset_iterator(p); -} - -#pragma region Folder Watcher -// Example use in exception based code: -// auto watcher = wil::make_folder_watcher(folder.Path().c_str(), true, wil::allChangeEvents, []() -// { -// // respond -// }); -// -// Example use in result code based code: -// wil::unique_folder_watcher watcher; -// THROW_IF_FAILED(watcher.create(folder, true, wil::allChangeEvents, []() -// { -// // respond -// })); - -enum class FolderChangeEvent : DWORD -{ - ChangesLost = 0, // requires special handling, reset state as events were lost - Added = FILE_ACTION_ADDED, - Removed = FILE_ACTION_REMOVED, - Modified = FILE_ACTION_MODIFIED, - RenameOldName = FILE_ACTION_RENAMED_OLD_NAME, - RenameNewName = FILE_ACTION_RENAMED_NEW_NAME, -}; - -enum class FolderChangeEvents : DWORD -{ - None = 0, - FileName = FILE_NOTIFY_CHANGE_FILE_NAME, - DirectoryName = FILE_NOTIFY_CHANGE_DIR_NAME, - Attributes = FILE_NOTIFY_CHANGE_ATTRIBUTES, - FileSize = FILE_NOTIFY_CHANGE_SIZE, - LastWriteTime = FILE_NOTIFY_CHANGE_LAST_WRITE, - Security = FILE_NOTIFY_CHANGE_SECURITY, - All = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY -}; -DEFINE_ENUM_FLAG_OPERATORS(FolderChangeEvents); - -/// @cond -namespace details -{ - struct folder_watcher_state - { - folder_watcher_state(wistd::function&& callback) : m_callback(wistd::move(callback)) + for (;;) { + // skip "." and ".." + if (!(WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && path_is_dot_or_dotdot(fd.cFileName))) + { + // Need to form an extended length path to provide the ability to delete paths > MAX_PATH + // and files with non-normalized names (dots or spaces at the end). + wil::unique_hlocal_string pathToDelete; + RETURN_IF_FAILED(::PathAllocCombine( + path.get(), fd.cFileName, + PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &pathToDelete)); + if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + // Get a handle to the directory to delete, preventing it from being replaced to prevent writes + // which could be used to bypass permission checks, and verify that it is not a name surrogate (e.g. + // symlink, mount point, etc). + wil::unique_hfile recursivelyDeletableDirectoryHandle = + TryCreateFileCanRecurseIntoDirectory(pathToDelete.get(), &fd); + if (recursivelyDeletableDirectoryHandle) + { + RemoveDirectoryOptions localOptions = options; + RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow( + pathToDelete.get(), WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory), + recursivelyDeletableDirectoryHandle.get())); + } + else if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + // This is a directory reparse point that should not be recursed. Delete it without traversing + // into it. + RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(pathToDelete.get())); + } + else + { + // Failed to grab a handle to the file or to read its attributes. This is not safe to recurse. + RETURN_WIN32(::GetLastError()); + } + } + else + { + // Try a DeleteFile. Some errors may be recoverable. + if (!::DeleteFileW(pathToDelete.get())) + { + // Fail for anything other than ERROR_ACCESS_DENIED with option to RemoveReadOnly available + bool potentiallyFixableReadOnlyProblem = + WI_IsFlagSet(options, RemoveDirectoryOptions::RemoveReadOnly) && + ::GetLastError() == ERROR_ACCESS_DENIED; + RETURN_LAST_ERROR_IF(!potentiallyFixableReadOnlyProblem); + + // Fail if the file does not have read-only set, likely just an ACL problem + DWORD fileAttr = ::GetFileAttributesW(pathToDelete.get()); + RETURN_LAST_ERROR_IF(!WI_IsFlagSet(fileAttr, FILE_ATTRIBUTE_READONLY)); + + // Remove read-only flag, setting to NORMAL if completely empty + WI_ClearFlag(fileAttr, FILE_ATTRIBUTE_READONLY); + if (fileAttr == 0) + { + fileAttr = FILE_ATTRIBUTE_NORMAL; + } + + // Set the new attributes and try to delete the file again, returning any failure + ::SetFileAttributesW(pathToDelete.get(), fileAttr); + RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get())); + } + } + } + + if (!::FindNextFileW(findHandle.get(), &fd)) + { + auto const err = ::GetLastError(); + if (err == ERROR_NO_MORE_FILES) + { + break; + } + RETURN_WIN32(err); + } } - wistd::function m_callback; - // Order is important, need to close the thread pool wait before the change handle. - unique_hfind_change m_findChangeHandle; - unique_threadpool_wait m_threadPoolWait; - }; - inline void delete_folder_watcher_state(_In_opt_ folder_watcher_state* storage) - { - delete storage; - } - - typedef resource_policy - folder_watcher_state_resource_policy; -} // namespace details -/// @endcond - -template -class folder_watcher_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit folder_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) - { - } - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - folder_watcher_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(folderToWatch, isRecursive, filter, wistd::move(callback)); - } - - result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); - } - -private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback(PTP_CALLBACK_INSTANCE /*Instance*/, void* context, TP_WAIT* pThreadPoolWait, TP_WAIT_RESULT /*result*/) - { - auto watcherState = static_cast(context); - watcherState->m_callback(); - - // Rearm the wait. Should not fail with valid parameters. - FindNextChangeNotification(watcherState->m_findChangeHandle.get()); - SetThreadpoolWait(pThreadPoolWait, watcherState->m_findChangeHandle.get(), __nullptr); - } - - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - wistd::unique_ptr watcherState(new (std::nothrow) - details::folder_watcher_state(wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - - watcherState->m_findChangeHandle.reset(FindFirstChangeNotificationW(folderToWatch, isRecursive, static_cast(filter))); - RETURN_LAST_ERROR_IF(!watcherState->m_findChangeHandle); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(&folder_watcher_t::callback, watcherState.get(), __nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - this->reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(this->get()->m_threadPoolWait.get(), this->get()->m_findChangeHandle.get(), __nullptr); + if (WI_IsFlagClear(options, RemoveDirectoryOptions::KeepRootDirectory)) + { + if (deleteHandle != INVALID_HANDLE_VALUE) + { +#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) + // DeleteFile and RemoveDirectory use POSIX delete, falling back to non-POSIX on most errors. Do the + // same here. + FILE_DISPOSITION_INFO_EX fileInfoEx{}; + fileInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + if (!SetFileInformationByHandle(deleteHandle, FileDispositionInfoEx, &fileInfoEx, sizeof(fileInfoEx))) + { + auto const err = ::GetLastError(); + // The real error we're looking for is STATUS_CANNOT_DELETE, but that's mapped to + // ERROR_ACCESS_DENIED. + if (err != ERROR_ACCESS_DENIED) + { +#endif + FILE_DISPOSITION_INFO fileInfo{}; + fileInfo.DeleteFile = TRUE; + RETURN_IF_WIN32_BOOL_FALSE( + SetFileInformationByHandle(deleteHandle, FileDispositionInfo, &fileInfo, sizeof(fileInfo))); +#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) + } + else + { + RETURN_WIN32(err); + } + } +#endif + } + else + { + RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get())); + } + } return S_OK; } -}; - -typedef unique_any_t, err_returncode_policy>> unique_folder_watcher_nothrow; - -inline unique_folder_watcher_nothrow make_folder_watcher_nothrow( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) WI_NOEXCEPT -{ - unique_folder_watcher_nothrow watcher; - watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} #ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_folder_watcher; + inline void RemoveDirectoryRecursive(PCWSTR path, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) + { + THROW_IF_FAILED(RemoveDirectoryRecursiveNoThrow(path, options)); + } +#endif // WIL_ENABLE_EXCEPTIONS -inline unique_folder_watcher make_folder_watcher( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) -{ - return unique_folder_watcher(folderToWatch, isRecursive, filter, wistd::move(callback)); -} + // Range based for that supports Win32 structures that use NextEntryOffset as the basis of traversing + // a result buffer that contains data. This is used in the following FileIO calls: + // FileStreamInfo, FILE_STREAM_INFO + // FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO + // FileFullDirectoryInfo, FILE_FULL_DIR_INFO + // FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO + // ReadDirectoryChangesW, FILE_NOTIFY_INFORMATION + + template struct next_entry_offset_iterator + { + // Fulfill std::iterator_traits requirements + using difference_type = ptrdiff_t; + using value_type = T; + using pointer = const T *; + using reference = const T &; +#if WIL_USE_STL + using iterator_category = ::std::forward_iterator_tag; +#endif + + next_entry_offset_iterator(T *iterable = __nullptr) : current_(iterable) + { + } + + // range based for requires operator!=, operator++ and operator* to do its work + // on the type returned from begin() and end(), provide those here. + WI_NODISCARD bool operator!=(const next_entry_offset_iterator &other) const + { + return current_ != other.current_; + } + + next_entry_offset_iterator &operator++() + { + current_ = + (current_->NextEntryOffset != 0) + ? reinterpret_cast(reinterpret_cast(current_) + current_->NextEntryOffset) + : __nullptr; + return *this; + } + + next_entry_offset_iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + WI_NODISCARD reference operator*() const WI_NOEXCEPT + { + return *current_; + } + WI_NODISCARD pointer operator->() const WI_NOEXCEPT + { + return current_; + } + + next_entry_offset_iterator begin() + { + return *this; + } + next_entry_offset_iterator end() + { + return next_entry_offset_iterator(); + } + + T *current_; + }; + + template next_entry_offset_iterator create_next_entry_offset_iterator(T *p) + { + return next_entry_offset_iterator(p); + } + +#pragma region Folder Watcher + // Example use in exception based code: + // auto watcher = wil::make_folder_watcher(folder.Path().c_str(), true, wil::allChangeEvents, []() + // { + // // respond + // }); + // + // Example use in result code based code: + // wil::unique_folder_watcher watcher; + // THROW_IF_FAILED(watcher.create(folder, true, wil::allChangeEvents, []() + // { + // // respond + // })); + + enum class FolderChangeEvent : DWORD + { + ChangesLost = 0, // requires special handling, reset state as events were lost + Added = FILE_ACTION_ADDED, + Removed = FILE_ACTION_REMOVED, + Modified = FILE_ACTION_MODIFIED, + RenameOldName = FILE_ACTION_RENAMED_OLD_NAME, + RenameNewName = FILE_ACTION_RENAMED_NEW_NAME, + }; + + enum class FolderChangeEvents : DWORD + { + None = 0, + FileName = FILE_NOTIFY_CHANGE_FILE_NAME, + DirectoryName = FILE_NOTIFY_CHANGE_DIR_NAME, + Attributes = FILE_NOTIFY_CHANGE_ATTRIBUTES, + FileSize = FILE_NOTIFY_CHANGE_SIZE, + LastWriteTime = FILE_NOTIFY_CHANGE_LAST_WRITE, + Security = FILE_NOTIFY_CHANGE_SECURITY, + All = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY + }; + DEFINE_ENUM_FLAG_OPERATORS(FolderChangeEvents); + + /// @cond + namespace details + { + struct folder_watcher_state + { + folder_watcher_state(wistd::function &&callback) : m_callback(wistd::move(callback)) + { + } + wistd::function m_callback; + // Order is important, need to close the thread pool wait before the change handle. + unique_hfind_change m_findChangeHandle; + unique_threadpool_wait m_threadPoolWait; + }; + + inline void delete_folder_watcher_state(_In_opt_ folder_watcher_state *storage) + { + delete storage; + } + + typedef resource_policy + folder_watcher_state_resource_policy; + } // namespace details + /// @endcond + + template class folder_watcher_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit folder_watcher_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) + { + } + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + folder_watcher_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions; use the create method"); + create(folderToWatch, isRecursive, filter, wistd::move(callback)); + } + + result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); + } + + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE /*Instance*/, void *context, TP_WAIT *pThreadPoolWait, + TP_WAIT_RESULT /*result*/) + { + auto watcherState = static_cast(context); + watcherState->m_callback(); + + // Rearm the wait. Should not fail with valid parameters. + FindNextChangeNotification(watcherState->m_findChangeHandle.get()); + SetThreadpoolWait(pThreadPoolWait, watcherState->m_findChangeHandle.get(), __nullptr); + } + + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + wistd::unique_ptr watcherState( + new (std::nothrow) details::folder_watcher_state(wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + + watcherState->m_findChangeHandle.reset( + FindFirstChangeNotificationW(folderToWatch, isRecursive, static_cast(filter))); + RETURN_LAST_ERROR_IF(!watcherState->m_findChangeHandle); + + watcherState->m_threadPoolWait.reset( + CreateThreadpoolWait(&folder_watcher_t::callback, watcherState.get(), __nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + this->reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(this->get()->m_threadPoolWait.get(), this->get()->m_findChangeHandle.get(), __nullptr); + return S_OK; + } + }; + + typedef unique_any_t< + folder_watcher_t, err_returncode_policy>> + unique_folder_watcher_nothrow; + + inline unique_folder_watcher_nothrow make_folder_watcher_nothrow(PCWSTR folderToWatch, bool isRecursive, + FolderChangeEvents filter, + wistd::function &&callback) WI_NOEXCEPT + { + unique_folder_watcher_nothrow watcher; + watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t< + folder_watcher_t, err_exception_policy>> + unique_folder_watcher; + + inline unique_folder_watcher make_folder_watcher(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + return unique_folder_watcher(folderToWatch, isRecursive, filter, wistd::move(callback)); + } #endif // WIL_ENABLE_EXCEPTIONS #pragma endregion #pragma region Folder Reader -// Example use for throwing: -// auto reader = wil::make_folder_change_reader(folder.Path().c_str(), true, wil::FolderChangeEvents::All, -// [](wil::FolderChangeEvent event, PCWSTR fileName) -// { -// switch (event) -// { -// case wil::FolderChangeEvent::ChangesLost: break; -// case wil::FolderChangeEvent::Added: break; -// case wil::FolderChangeEvent::Removed: break; -// case wil::FolderChangeEvent::Modified: break; -// case wil::FolderChangeEvent::RenamedOldName: break; -// case wil::FolderChangeEvent::RenamedNewName: break; -// }); -// -// Example use for non throwing: -// wil::unique_folder_change_reader_nothrow reader; -// THROW_IF_FAILED(reader.create(folder, true, wil::FolderChangeEvents::All, -// [](wil::FolderChangeEvent event, PCWSTR fileName) -// { -// // handle changes -// })); -// + // Example use for throwing: + // auto reader = wil::make_folder_change_reader(folder.Path().c_str(), true, wil::FolderChangeEvents::All, + // [](wil::FolderChangeEvent event, PCWSTR fileName) + // { + // switch (event) + // { + // case wil::FolderChangeEvent::ChangesLost: break; + // case wil::FolderChangeEvent::Added: break; + // case wil::FolderChangeEvent::Removed: break; + // case wil::FolderChangeEvent::Modified: break; + // case wil::FolderChangeEvent::RenamedOldName: break; + // case wil::FolderChangeEvent::RenamedNewName: break; + // }); + // + // Example use for non throwing: + // wil::unique_folder_change_reader_nothrow reader; + // THROW_IF_FAILED(reader.create(folder, true, wil::FolderChangeEvents::All, + // [](wil::FolderChangeEvent event, PCWSTR fileName) + // { + // // handle changes + // })); + // -/// @cond -namespace details -{ - struct folder_change_reader_state + /// @cond + namespace details { - folder_change_reader_state(bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) : - m_callback(wistd::move(callback)), m_isRecursive(isRecursive), m_filter(filter) + struct folder_change_reader_state { - } - - ~folder_change_reader_state() - { - if (m_tpIo != __nullptr) + folder_change_reader_state(bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + : m_callback(wistd::move(callback)), m_isRecursive(isRecursive), m_filter(filter) { - TP_IO* tpIo = m_tpIo; - - // Indicate to the callback function that this object is being torn - // down. + } + ~folder_change_reader_state() + { + if (m_tpIo != __nullptr) { - auto autoLock = m_cancelLock.lock_exclusive(); - m_tpIo = __nullptr; - } + TP_IO *tpIo = m_tpIo; - // Cancel IO to terminate the file system monitoring operation. + // Indicate to the callback function that this object is being torn + // down. - if (m_folderHandle) - { - BOOL cancelRes = CancelIoEx(m_folderHandle.get(), &m_overlapped); - - // no pending operation to cancel. Maybe StartIo returned - // an error? - if (!(cancelRes == FALSE && ::GetLastError() == ERROR_NOT_FOUND)) { - DWORD bytesTransferredIgnored = 0; - GetOverlappedResult(m_folderHandle.get(), &m_overlapped, &bytesTransferredIgnored, TRUE); + auto autoLock = m_cancelLock.lock_exclusive(); + m_tpIo = __nullptr; } + + // Cancel IO to terminate the file system monitoring operation. + + if (m_folderHandle) + { + BOOL cancelRes = CancelIoEx(m_folderHandle.get(), &m_overlapped); + + // no pending operation to cancel. Maybe StartIo returned + // an error? + if (!(cancelRes == FALSE && ::GetLastError() == ERROR_NOT_FOUND)) + { + DWORD bytesTransferredIgnored = 0; + GetOverlappedResult(m_folderHandle.get(), &m_overlapped, &bytesTransferredIgnored, TRUE); + } + } + + // Wait for callbacks to complete. + // + // N.B. This is a blocking call and must not be made within a + // callback or within a lock which is taken inside the + // callback. + + WaitForThreadpoolIoCallbacks(tpIo, TRUE); + CloseThreadpoolIo(tpIo); } - - // Wait for callbacks to complete. - // - // N.B. This is a blocking call and must not be made within a - // callback or within a lock which is taken inside the - // callback. - - WaitForThreadpoolIoCallbacks(tpIo, TRUE); - CloseThreadpoolIo(tpIo); } - } - HRESULT StartIo() - { - // Unfortunately we have to handle ref-counting of IOs on behalf of the - // thread pool. - StartThreadpoolIo(m_tpIo); - HRESULT hr = - ReadDirectoryChangesW( - m_folderHandle.get(), m_readBuffer, sizeof(m_readBuffer), m_isRecursive, static_cast(m_filter), __nullptr, &m_overlapped, __nullptr) - ? S_OK - : HRESULT_FROM_WIN32(::GetLastError()); - if (FAILED(hr)) + HRESULT StartIo() { - // This operation does not have the usual semantic of returning - // ERROR_IO_PENDING. - // WI_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)); + // Unfortunately we have to handle ref-counting of IOs on behalf of the + // thread pool. + StartThreadpoolIo(m_tpIo); + HRESULT hr = + ReadDirectoryChangesW(m_folderHandle.get(), m_readBuffer, sizeof(m_readBuffer), m_isRecursive, + static_cast(m_filter), __nullptr, &m_overlapped, __nullptr) + ? S_OK + : HRESULT_FROM_WIN32(::GetLastError()); + if (FAILED(hr)) + { + // This operation does not have the usual semantic of returning + // ERROR_IO_PENDING. + // WI_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)); - // If the operation failed for whatever reason, ensure the TP - // ref counts are accurate. + // If the operation failed for whatever reason, ensure the TP + // ref counts are accurate. - CancelThreadpoolIo(m_tpIo); + CancelThreadpoolIo(m_tpIo); + } + return hr; } - return hr; + + // void (wil::FolderChangeEvent event, PCWSTR fileName) + wistd::function m_callback; + unique_handle m_folderHandle; + BOOL m_isRecursive = FALSE; + FolderChangeEvents m_filter = FolderChangeEvents::None; + OVERLAPPED m_overlapped{}; + TP_IO *m_tpIo = __nullptr; + srwlock m_cancelLock; + unsigned char m_readBuffer[4096]{}; // Consider alternative buffer sizes. With 512 byte buffer i was not + // able to observe overflow. + }; + + inline void delete_folder_change_reader_state(_In_opt_ folder_change_reader_state *storage) + { + delete storage; } - // void (wil::FolderChangeEvent event, PCWSTR fileName) - wistd::function m_callback; - unique_handle m_folderHandle; - BOOL m_isRecursive = FALSE; - FolderChangeEvents m_filter = FolderChangeEvents::None; - OVERLAPPED m_overlapped{}; - TP_IO* m_tpIo = __nullptr; - srwlock m_cancelLock; - unsigned char m_readBuffer[4096]{}; // Consider alternative buffer sizes. With 512 byte buffer i was not able to observe overflow. - }; + typedef resource_policy + folder_change_reader_state_resource_policy; + } // namespace details + /// @endcond - inline void delete_folder_change_reader_state(_In_opt_ folder_change_reader_state* storage) + template + class folder_change_reader_t : public storage_t { - delete storage; - } - - typedef resource_policy - folder_change_reader_state_resource_policy; -} // namespace details -/// @endcond - -template -class folder_change_reader_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit folder_change_reader_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) - { - } - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - folder_change_reader_t( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(folderToWatch, isRecursive, filter, wistd::move(callback)); - } - - result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); - } - - wil::unique_hfile& folder_handle() - { - return this->get()->m_folderHandle; - } - -private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback( - PTP_CALLBACK_INSTANCE /* Instance */, void* context, void* /*overlapped*/, ULONG result, ULONG_PTR /* BytesTransferred */, TP_IO* /* Io */) - { - auto readerState = static_cast(context); - // WI_ASSERT(overlapped == &readerState->m_overlapped); - - if (result == ERROR_SUCCESS) + public: + // forward all base class constructors... + template + explicit folder_change_reader_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) { - for (auto const& info : - create_next_entry_offset_iterator(reinterpret_cast(readerState->m_readBuffer))) - { - wchar_t relativeFileName[MAX_PATH]; - StringCchCopyNW( - relativeFileName, ARRAYSIZE(relativeFileName), info.FileName, info.FileNameLength / sizeof(info.FileName[0])); + } - readerState->m_callback(static_cast(info.Action), relativeFileName); + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + folder_change_reader_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions; use the create method"); + create(folderToWatch, isRecursive, filter, wistd::move(callback)); + } + + result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); + } + + wil::unique_hfile &folder_handle() + { + return this->get()->m_folderHandle; + } + + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE /* Instance */, void *context, void * /*overlapped*/, + ULONG result, ULONG_PTR /* BytesTransferred */, TP_IO * /* Io */) + { + auto readerState = static_cast(context); + // WI_ASSERT(overlapped == &readerState->m_overlapped); + + if (result == ERROR_SUCCESS) + { + for (auto const &info : create_next_entry_offset_iterator( + reinterpret_cast(readerState->m_readBuffer))) + { + wchar_t relativeFileName[MAX_PATH]; + StringCchCopyNW(relativeFileName, ARRAYSIZE(relativeFileName), info.FileName, + info.FileNameLength / sizeof(info.FileName[0])); + + readerState->m_callback(static_cast(info.Action), relativeFileName); + } } - } - else if (result == ERROR_NOTIFY_ENUM_DIR) - { - readerState->m_callback(FolderChangeEvent::ChangesLost, __nullptr); - } - else - { - // No need to requeue - return; - } - - // If the lock is held non-shared or the TP IO is nullptr, this - // structure is being torn down. Otherwise, monitor for further - // changes. - auto autoLock = readerState->m_cancelLock.try_lock_shared(); - if (autoLock && readerState->m_tpIo) - { - readerState->StartIo(); // ignoring failure here - } - } - - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) - { - wistd::unique_ptr readerState( - new (std::nothrow) details::folder_change_reader_state(isRecursive, filter, wistd::move(callback))); - RETURN_IF_NULL_ALLOC(readerState); - - readerState->m_folderHandle.reset(CreateFileW( - folderToWatch, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, - __nullptr, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, - __nullptr)); - RETURN_LAST_ERROR_IF(!readerState->m_folderHandle); - - readerState->m_tpIo = - CreateThreadpoolIo(readerState->m_folderHandle.get(), &folder_change_reader_t::callback, readerState.get(), __nullptr); - RETURN_LAST_ERROR_IF_NULL(readerState->m_tpIo); - RETURN_IF_FAILED(readerState->StartIo()); - this->reset(readerState.release()); - return S_OK; - } -}; - -typedef unique_any_t, err_returncode_policy>> unique_folder_change_reader_nothrow; - -inline unique_folder_change_reader_nothrow make_folder_change_reader_nothrow( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) WI_NOEXCEPT -{ - unique_folder_change_reader_nothrow watcher; - watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} - -#ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_folder_change_reader; - -inline unique_folder_change_reader make_folder_change_reader( - PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function&& callback) -{ - return unique_folder_change_reader(folderToWatch, isRecursive, filter, wistd::move(callback)); -} -#endif // WIL_ENABLE_EXCEPTIONS -#pragma endregion - -//! Dos and VolumeGuid paths are always extended length paths with the \\?\ prefix. -enum class VolumePrefix -{ - Dos = VOLUME_NAME_DOS, // Extended Dos Device path form, e.g. \\?\C:\Users\Chris\AppData\Local\Temp\wil8C31.tmp - VolumeGuid = VOLUME_NAME_GUID, // \\?\Volume{588fb606-b95b-4eae-b3cb-1e49861aaf18}\Users\Chris\AppData\Local\Temp\wil8C31.tmp - // The following are special paths which can't be used with Win32 APIs, but are useful in other scenarios. - None = VOLUME_NAME_NONE, // Path without the volume root, e.g. \Users\Chris\AppData\Local\Temp\wil8C31.tmp - NtObjectName = VOLUME_NAME_NT, // Unique name used by Object Manager, e.g. \Device\HarddiskVolume4\Users\Chris\AppData\Local\Temp\wil8C31.tmp -}; -enum class PathOptions -{ - Normalized = FILE_NAME_NORMALIZED, - Opened = FILE_NAME_OPENED, -}; -DEFINE_ENUM_FLAG_OPERATORS(PathOptions); - -/** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. -Get the full path name in different forms -Use this instead + VolumePrefix::None instead of GetFileInformationByHandleEx(FileNameInfo) to -get that path form. */ -template -HRESULT GetFinalPathNameByHandleW( - HANDLE fileHandle, - string_type& path, - wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, - wil::PathOptions options = wil::PathOptions::Normalized) -{ - return AdaptFixedSizeToAllocatedResult( - path, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT { - *valueLengthNeededWithNull = ::GetFinalPathNameByHandleW( - fileHandle, value, static_cast(valueLength), static_cast(volumePrefix) | static_cast(options)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) + else if (result == ERROR_NOTIFY_ENUM_DIR) { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -/** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. -Get the full path name in different forms. Use this + VolumePrefix::None -instead of GetFileInformationByHandleEx(FileNameInfo) to get that path form. */ -template -string_type GetFinalPathNameByHandleW( - HANDLE fileHandle, wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, wil::PathOptions options = wil::PathOptions::Normalized) -{ - string_type result{}; - THROW_IF_FAILED((GetFinalPathNameByHandleW(fileHandle, result, volumePrefix, options))); - return result; -} -#endif - -//! A strongly typed version of the Win32 API of GetCurrentDirectoryW. -//! Return a path in an allocated buffer for handling long paths. -template -HRESULT GetCurrentDirectoryW(string_type& path) -{ - return AdaptFixedSizeToAllocatedResult( - path, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT { - *valueLengthNeededWithNull = ::GetCurrentDirectoryW(static_cast(valueLength), value); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) - { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! A strongly typed version of the Win32 API of GetCurrentDirectoryW. -//! Return a path in an allocated buffer for handling long paths. -template -string_type GetCurrentDirectoryW() -{ - string_type result{}; - THROW_IF_FAILED((GetCurrentDirectoryW(result))); - return result; -} -#endif - -// TODO: add support for these and other similar APIs. -// GetShortPathNameW() -// GetLongPathNameW() -// GetTempDirectory() - -/// @cond -namespace details -{ - template - struct MapInfoClassToInfoStruct; // failure to map is a usage error caught by the compiler -#define MAP_INFOCLASS_TO_STRUCT(InfoClass, InfoStruct, IsFixed, Extra) \ - template <> \ - struct MapInfoClassToInfoStruct \ - { \ - typedef InfoStruct type; \ - static bool const isFixed = IsFixed; \ - static size_t const extraSize = Extra; \ - }; - - MAP_INFOCLASS_TO_STRUCT(FileBasicInfo, FILE_BASIC_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileStandardInfo, FILE_STANDARD_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileNameInfo, FILE_NAME_INFO, false, 64); - MAP_INFOCLASS_TO_STRUCT(FileRenameInfo, FILE_RENAME_INFO, false, 64); - MAP_INFOCLASS_TO_STRUCT(FileDispositionInfo, FILE_DISPOSITION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAllocationInfo, FILE_ALLOCATION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileEndOfFileInfo, FILE_END_OF_FILE_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileStreamInfo, FILE_STREAM_INFO, false, 64); - MAP_INFOCLASS_TO_STRUCT(FileCompressionInfo, FILE_COMPRESSION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAttributeTagInfo, FILE_ATTRIBUTE_TAG_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO, false, 8192); - MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryRestartInfo, FILE_ID_BOTH_DIR_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIoPriorityHintInfo, FILE_IO_PRIORITY_HINT_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileRemoteProtocolInfo, FILE_REMOTE_PROTOCOL_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryInfo, FILE_FULL_DIR_INFO, false, 8192); - MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryRestartInfo, FILE_FULL_DIR_INFO, true, 0); -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - MAP_INFOCLASS_TO_STRUCT(FileStorageInfo, FILE_STORAGE_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAlignmentInfo, FILE_ALIGNMENT_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdInfo, FILE_ID_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO, false, 8192); - MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryRestartInfo, FILE_ID_EXTD_DIR_INFO, true, 0); -#endif - - // Type unsafe version used in the implementation to avoid template bloat. - inline HRESULT GetFileInfo(HANDLE fileHandle, FILE_INFO_BY_HANDLE_CLASS infoClass, size_t allocationSize, _Outptr_result_maybenull_ void** result) - { - *result = nullptr; - - wistd::unique_ptr resultHolder(new (std::nothrow) char[allocationSize]); - RETURN_IF_NULL_ALLOC(resultHolder); - - for (;;) - { - if (GetFileInformationByHandleEx(fileHandle, infoClass, resultHolder.get(), static_cast(allocationSize))) - { - *result = resultHolder.release(); - break; + readerState->m_callback(FolderChangeEvent::ChangesLost, __nullptr); } else { - DWORD const lastError = ::GetLastError(); - if (lastError == ERROR_MORE_DATA) + // No need to requeue + return; + } + + // If the lock is held non-shared or the TP IO is nullptr, this + // structure is being torn down. Otherwise, monitor for further + // changes. + auto autoLock = readerState->m_cancelLock.try_lock_shared(); + if (autoLock && readerState->m_tpIo) + { + readerState->StartIo(); // ignoring failure here + } + } + + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + wistd::unique_ptr readerState( + new (std::nothrow) details::folder_change_reader_state(isRecursive, filter, wistd::move(callback))); + RETURN_IF_NULL_ALLOC(readerState); + + readerState->m_folderHandle.reset( + CreateFileW(folderToWatch, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, + __nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, __nullptr)); + RETURN_LAST_ERROR_IF(!readerState->m_folderHandle); + + readerState->m_tpIo = CreateThreadpoolIo(readerState->m_folderHandle.get(), + &folder_change_reader_t::callback, readerState.get(), __nullptr); + RETURN_LAST_ERROR_IF_NULL(readerState->m_tpIo); + RETURN_IF_FAILED(readerState->StartIo()); + this->reset(readerState.release()); + return S_OK; + } + }; + + typedef unique_any_t, err_returncode_policy>> + unique_folder_change_reader_nothrow; + + inline unique_folder_change_reader_nothrow make_folder_change_reader_nothrow( + PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) WI_NOEXCEPT + { + unique_folder_change_reader_nothrow watcher; + watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> + unique_folder_change_reader; + + inline unique_folder_change_reader make_folder_change_reader( + PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + return unique_folder_change_reader(folderToWatch, isRecursive, filter, wistd::move(callback)); + } +#endif // WIL_ENABLE_EXCEPTIONS +#pragma endregion + + //! Dos and VolumeGuid paths are always extended length paths with the \\?\ prefix. + enum class VolumePrefix + { + Dos = VOLUME_NAME_DOS, // Extended Dos Device path form, e.g. \\?\C:\Users\Chris\AppData\Local\Temp\wil8C31.tmp + VolumeGuid = + VOLUME_NAME_GUID, // \\?\Volume{588fb606-b95b-4eae-b3cb-1e49861aaf18}\Users\Chris\AppData\Local\Temp\wil8C31.tmp + // The following are special paths which can't be used with Win32 APIs, but are useful in other scenarios. + None = VOLUME_NAME_NONE, // Path without the volume root, e.g. \Users\Chris\AppData\Local\Temp\wil8C31.tmp + NtObjectName = VOLUME_NAME_NT, // Unique name used by Object Manager, e.g. + // \Device\HarddiskVolume4\Users\Chris\AppData\Local\Temp\wil8C31.tmp + }; + enum class PathOptions + { + Normalized = FILE_NAME_NORMALIZED, + Opened = FILE_NAME_OPENED, + }; + DEFINE_ENUM_FLAG_OPERATORS(PathOptions); + + /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. + Get the full path name in different forms + Use this instead + VolumePrefix::None instead of GetFileInformationByHandleEx(FileNameInfo) to + get that path form. */ + template + HRESULT GetFinalPathNameByHandleW(HANDLE fileHandle, string_type &path, + wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, + wil::PathOptions options = wil::PathOptions::Normalized) + { + return AdaptFixedSizeToAllocatedResult( + path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNull) -> HRESULT { + *valueLengthNeededWithNull = + ::GetFinalPathNameByHandleW(fileHandle, value, static_cast(valueLength), + static_cast(volumePrefix) | static_cast(options)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) { - allocationSize *= 2; - resultHolder.reset(new (std::nothrow) char[allocationSize]); - RETURN_IF_NULL_ALLOC(resultHolder); + (*valueLengthNeededWithNull)++; // it fit, account for the null } - else if (lastError == ERROR_NO_MORE_FILES) // for folder enumeration cases + return S_OK; + }); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. + Get the full path name in different forms. Use this + VolumePrefix::None + instead of GetFileInformationByHandleEx(FileNameInfo) to get that path form. */ + template + string_type GetFinalPathNameByHandleW(HANDLE fileHandle, wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, + wil::PathOptions options = wil::PathOptions::Normalized) + { + string_type result{}; + THROW_IF_FAILED( + (GetFinalPathNameByHandleW(fileHandle, result, volumePrefix, options))); + return result; + } +#endif + + //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. + //! Return a path in an allocated buffer for handling long paths. + template HRESULT GetCurrentDirectoryW(string_type &path) + { + return AdaptFixedSizeToAllocatedResult( + path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNull) -> HRESULT { + *valueLengthNeededWithNull = ::GetCurrentDirectoryW(static_cast(valueLength), value); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) { - break; + (*valueLengthNeededWithNull)++; // it fit, account for the null } - else if (lastError == ERROR_INVALID_PARAMETER) // operation not supported by file system - { - return HRESULT_FROM_WIN32(lastError); - } - else if ((lastError == ERROR_HANDLE_EOF) && (infoClass == FileStreamInfo)) + return S_OK; + }); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. + //! Return a path in an allocated buffer for handling long paths. + template + string_type GetCurrentDirectoryW() + { + string_type result{}; + THROW_IF_FAILED((GetCurrentDirectoryW(result))); + return result; + } +#endif + + // TODO: add support for these and other similar APIs. + // GetShortPathNameW() + // GetLongPathNameW() + // GetTempDirectory() + + /// @cond + namespace details + { + template + struct MapInfoClassToInfoStruct; // failure to map is a usage error caught by the compiler +#define MAP_INFOCLASS_TO_STRUCT(InfoClass, InfoStruct, IsFixed, Extra) \ + template <> struct MapInfoClassToInfoStruct \ + { \ + typedef InfoStruct type; \ + static bool const isFixed = IsFixed; \ + static size_t const extraSize = Extra; \ + }; + + MAP_INFOCLASS_TO_STRUCT(FileBasicInfo, FILE_BASIC_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileStandardInfo, FILE_STANDARD_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileNameInfo, FILE_NAME_INFO, false, 64); + MAP_INFOCLASS_TO_STRUCT(FileRenameInfo, FILE_RENAME_INFO, false, 64); + MAP_INFOCLASS_TO_STRUCT(FileDispositionInfo, FILE_DISPOSITION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAllocationInfo, FILE_ALLOCATION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileEndOfFileInfo, FILE_END_OF_FILE_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileStreamInfo, FILE_STREAM_INFO, false, 64); + MAP_INFOCLASS_TO_STRUCT(FileCompressionInfo, FILE_COMPRESSION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAttributeTagInfo, FILE_ATTRIBUTE_TAG_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO, false, 8192); + MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryRestartInfo, FILE_ID_BOTH_DIR_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIoPriorityHintInfo, FILE_IO_PRIORITY_HINT_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileRemoteProtocolInfo, FILE_REMOTE_PROTOCOL_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryInfo, FILE_FULL_DIR_INFO, false, 8192); + MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryRestartInfo, FILE_FULL_DIR_INFO, true, 0); +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + MAP_INFOCLASS_TO_STRUCT(FileStorageInfo, FILE_STORAGE_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAlignmentInfo, FILE_ALIGNMENT_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdInfo, FILE_ID_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO, false, 8192); + MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryRestartInfo, FILE_ID_EXTD_DIR_INFO, true, 0); +#endif + + // Type unsafe version used in the implementation to avoid template bloat. + inline HRESULT GetFileInfo(HANDLE fileHandle, FILE_INFO_BY_HANDLE_CLASS infoClass, size_t allocationSize, + _Outptr_result_maybenull_ void **result) + { + *result = nullptr; + + wistd::unique_ptr resultHolder(new (std::nothrow) char[allocationSize]); + RETURN_IF_NULL_ALLOC(resultHolder); + + for (;;) + { + if (GetFileInformationByHandleEx(fileHandle, infoClass, resultHolder.get(), + static_cast(allocationSize))) { + *result = resultHolder.release(); break; } else { - RETURN_WIN32(lastError); + DWORD const lastError = ::GetLastError(); + if (lastError == ERROR_MORE_DATA) + { + allocationSize *= 2; + resultHolder.reset(new (std::nothrow) char[allocationSize]); + RETURN_IF_NULL_ALLOC(resultHolder); + } + else if (lastError == ERROR_NO_MORE_FILES) // for folder enumeration cases + { + break; + } + else if (lastError == ERROR_INVALID_PARAMETER) // operation not supported by file system + { + return HRESULT_FROM_WIN32(lastError); + } + else if ((lastError == ERROR_HANDLE_EOF) && (infoClass == FileStreamInfo)) + { + break; + } + else + { + RETURN_WIN32(lastError); + } } } + return S_OK; } + } // namespace details + /// @endcond + + /** Get file information for a variable sized structure, returns an HRESULT. + ~~~ + wistd::unique_ptr fileNameInfo; + RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, fileNameInfo)); + ~~~ + */ + template ::isFixed, int>::type = 0> + HRESULT GetFileInfoNoThrow(HANDLE fileHandle, + wistd::unique_ptr::type> &result) + WI_NOEXCEPT + { + void *rawResult; + HRESULT hr = details::GetFileInfo(fileHandle, infoClass, + sizeof(typename details::MapInfoClassToInfoStruct::type) + + details::MapInfoClassToInfoStruct::extraSize, + &rawResult); + result.reset(static_cast::type *>(rawResult)); + RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system + RETURN_IF_FAILED(hr); return S_OK; } -} // namespace details -/// @endcond -/** Get file information for a variable sized structure, returns an HRESULT. -~~~ -wistd::unique_ptr fileNameInfo; -RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, fileNameInfo)); -~~~ -*/ -template ::isFixed, int>::type = 0> -HRESULT GetFileInfoNoThrow(HANDLE fileHandle, wistd::unique_ptr::type>& result) WI_NOEXCEPT -{ - void* rawResult; - HRESULT hr = details::GetFileInfo( - fileHandle, - infoClass, - sizeof(typename details::MapInfoClassToInfoStruct::type) + details::MapInfoClassToInfoStruct::extraSize, - &rawResult); - result.reset(static_cast::type*>(rawResult)); - RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system - RETURN_IF_FAILED(hr); - return S_OK; -} + /** Get file information for a fixed sized structure, returns an HRESULT. + ~~~ + FILE_BASIC_INFO fileBasicInfo; + RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, &fileBasicInfo)); + ~~~ + */ + template ::isFixed, int>::type = 0> + HRESULT GetFileInfoNoThrow(HANDLE fileHandle, + _Out_ typename details::MapInfoClassToInfoStruct::type *result) WI_NOEXCEPT + { + const HRESULT hr = GetFileInformationByHandleEx(fileHandle, infoClass, result, sizeof(*result)) + ? S_OK + : HRESULT_FROM_WIN32(::GetLastError()); + RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system + RETURN_IF_FAILED(hr); + return S_OK; + } -/** Get file information for a fixed sized structure, returns an HRESULT. -~~~ -FILE_BASIC_INFO fileBasicInfo; -RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, &fileBasicInfo)); -~~~ -*/ -template ::isFixed, int>::type = 0> -HRESULT GetFileInfoNoThrow(HANDLE fileHandle, _Out_ typename details::MapInfoClassToInfoStruct::type* result) WI_NOEXCEPT -{ - const HRESULT hr = - GetFileInformationByHandleEx(fileHandle, infoClass, result, sizeof(*result)) ? S_OK : HRESULT_FROM_WIN32(::GetLastError()); - RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system - RETURN_IF_FAILED(hr); - return S_OK; -} + // Verifies that the given file path is not a hard or a soft link. If the file is present at the path, returns + // a handle to it without delete permissions to block an attacker from swapping the file. + inline HRESULT CreateFileAndEnsureNotLinked(PCWSTR path, wil::unique_hfile &fileHandle) + { + // Open handles to the original path and to the final path and compare each file's information + // to verify they are the same file. If they are different, the file is a soft link. + fileHandle.reset(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); + RETURN_LAST_ERROR_IF(!fileHandle); + BY_HANDLE_FILE_INFORMATION fileInfo; + RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(fileHandle.get(), &fileInfo)); -// Verifies that the given file path is not a hard or a soft link. If the file is present at the path, returns -// a handle to it without delete permissions to block an attacker from swapping the file. -inline HRESULT CreateFileAndEnsureNotLinked(PCWSTR path, wil::unique_hfile& fileHandle) -{ - // Open handles to the original path and to the final path and compare each file's information - // to verify they are the same file. If they are different, the file is a soft link. - fileHandle.reset(CreateFileW( - path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); - RETURN_LAST_ERROR_IF(!fileHandle); - BY_HANDLE_FILE_INFORMATION fileInfo; - RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(fileHandle.get(), &fileInfo)); + // Open a handle without the reparse point flag to get the final path in case it is a soft link. + wil::unique_hfile finalPathHandle( + CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr)); + RETURN_LAST_ERROR_IF(!finalPathHandle); + BY_HANDLE_FILE_INFORMATION finalFileInfo; + RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(finalPathHandle.get(), &finalFileInfo)); + finalPathHandle.reset(); - // Open a handle without the reparse point flag to get the final path in case it is a soft link. - wil::unique_hfile finalPathHandle(CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr)); - RETURN_LAST_ERROR_IF(!finalPathHandle); - BY_HANDLE_FILE_INFORMATION finalFileInfo; - RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(finalPathHandle.get(), &finalFileInfo)); - finalPathHandle.reset(); + // The low and high indices and volume serial number uniquely identify a file. These must match if they are the + // same file. + const bool isSoftLink = ((fileInfo.nFileIndexLow != finalFileInfo.nFileIndexLow) || + (fileInfo.nFileIndexHigh != finalFileInfo.nFileIndexHigh) || + (fileInfo.dwVolumeSerialNumber != finalFileInfo.dwVolumeSerialNumber)); - // The low and high indices and volume serial number uniquely identify a file. These must match if they are the same file. - const bool isSoftLink = - ((fileInfo.nFileIndexLow != finalFileInfo.nFileIndexLow) || (fileInfo.nFileIndexHigh != finalFileInfo.nFileIndexHigh) || - (fileInfo.dwVolumeSerialNumber != finalFileInfo.dwVolumeSerialNumber)); + // Return failure if it is a soft link or a hard link (number of links greater than 1). + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), (isSoftLink || fileInfo.nNumberOfLinks > 1)); - // Return failure if it is a soft link or a hard link (number of links greater than 1). - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), (isSoftLink || fileInfo.nNumberOfLinks > 1)); - - return S_OK; -} + return S_OK; + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Get file information for a fixed sized structure, throws on failure. -~~~ -auto fileBasicInfo = GetFileInfo(fileHandle); -~~~ -*/ -template ::isFixed, int>::type = 0> -typename details::MapInfoClassToInfoStruct::type GetFileInfo(HANDLE fileHandle) -{ - typename details::MapInfoClassToInfoStruct::type result{}; - THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, &result)); - return result; -} - -/** Get file information for a variable sized structure, throws on failure. -~~~ -auto fileBasicInfo = GetFileInfo(fileHandle); -~~~ -*/ -template ::isFixed, int>::type = 0> -wistd::unique_ptr::type> GetFileInfo(HANDLE fileHandle) -{ - wistd::unique_ptr::type> result; - THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, result)); - return result; -} - -// Helpers to make the CreateFileW API easier to use. -// https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-createfilew - -struct file_and_error_result -{ - file_and_error_result(HANDLE file_handle, DWORD error) : file(file_handle), last_error(error) + /** Get file information for a fixed sized structure, throws on failure. + ~~~ + auto fileBasicInfo = GetFileInfo(fileHandle); + ~~~ + */ + template ::isFixed, int>::type = 0> + typename details::MapInfoClassToInfoStruct::type GetFileInfo(HANDLE fileHandle) { + typename details::MapInfoClassToInfoStruct::type result{}; + THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, &result)); + return result; } - wil::unique_hfile file; - DWORD last_error{}; -}; - -/** Non-throwing open existing using OPEN_EXISTING, returns handle and error code. -~~~ -auto [handle, error] = wil::try_open_file(filePath.c_str()); -~~~ -*/ -inline file_and_error_result try_open_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ, - DWORD dwShareMode = FILE_SHARE_READ, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - bool inheritHandle = false) noexcept -{ - SECURITY_ATTRIBUTES secAttributes{sizeof(secAttributes)}; - secAttributes.bInheritHandle = inheritHandle; - auto handle = CreateFileW(path, dwDesiredAccess, dwShareMode, &secAttributes, OPEN_EXISTING, dwFlagsAndAttributes, nullptr); - return {handle, ::GetLastError()}; -} - -/** open existing using OPEN_EXISTING, throws on error. -~~~ -auto handle = wil::open_file(filePath.c_str()); -~~~ -*/ -inline wil::unique_hfile open_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ, - DWORD dwShareMode = FILE_SHARE_READ, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - bool inheritHandle = false) -{ - auto result = try_open_file(path, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, inheritHandle); - THROW_WIN32_IF(result.last_error, !result.file.is_valid()); - return wistd::move(result.file); -} - -/// @cond -namespace details -{ - template - file_and_error_result create_file( - PCWSTR path, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) noexcept + /** Get file information for a variable sized structure, throws on failure. + ~~~ + auto fileBasicInfo = GetFileInfo(fileHandle); + ~~~ + */ + template ::isFixed, int>::type = 0> + wistd::unique_ptr::type> GetFileInfo(HANDLE fileHandle) { - auto handle = CreateFileW( - path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreateDisposition, dwFlagsAndAttributes, hTemplateFile); + wistd::unique_ptr::type> result; + THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, result)); + return result; + } + + // Helpers to make the CreateFileW API easier to use. + // https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-createfilew + + struct file_and_error_result + { + file_and_error_result(HANDLE file_handle, DWORD error) : file(file_handle), last_error(error) + { + } + + wil::unique_hfile file; + DWORD last_error{}; + }; + + /** Non-throwing open existing using OPEN_EXISTING, returns handle and error code. + ~~~ + auto [handle, error] = wil::try_open_file(filePath.c_str()); + ~~~ + */ + inline file_and_error_result try_open_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ, + DWORD dwShareMode = FILE_SHARE_READ, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + bool inheritHandle = false) noexcept + { + SECURITY_ATTRIBUTES secAttributes{sizeof(secAttributes)}; + secAttributes.bInheritHandle = inheritHandle; + auto handle = CreateFileW(path, dwDesiredAccess, dwShareMode, &secAttributes, OPEN_EXISTING, + dwFlagsAndAttributes, nullptr); return {handle, ::GetLastError()}; } -} // namespace details -/// @endcond -/** create using CREATE_NEW, returns handle and error code. -~~~ -auto [handle, error] = wil::try_create_new_file(filePath.c_str()); -~~~ -*/ -inline file_and_error_result try_create_new_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) noexcept -{ - return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); -} + /** open existing using OPEN_EXISTING, throws on error. + ~~~ + auto handle = wil::open_file(filePath.c_str()); + ~~~ + */ + inline wil::unique_hfile open_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ, + DWORD dwShareMode = FILE_SHARE_READ, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, bool inheritHandle = false) + { + auto result = try_open_file(path, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, inheritHandle); + THROW_WIN32_IF(result.last_error, !result.file.is_valid()); + return wistd::move(result.file); + } -/** create using OPEN_ALWAYS, returns handle and error code. -~~~ -auto [handle, error] = wil::try_open_or_create_file(filePath.c_str()); -~~~ -*/ -inline file_and_error_result try_open_or_create_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) noexcept -{ - return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); -} + /// @cond + namespace details + { + template + file_and_error_result create_file(PCWSTR path, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile) noexcept + { + auto handle = CreateFileW(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreateDisposition, + dwFlagsAndAttributes, hTemplateFile); + return {handle, ::GetLastError()}; + } + } // namespace details + /// @endcond -/** create using CREATE_ALWAYS, returns handle and error code. -~~~ -auto [handle, error] = wil::try_open_or_truncate_existing_file(filePath.c_str()); -~~~ -*/ -inline file_and_error_result try_open_or_truncate_existing_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) noexcept -{ - return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); -} + /** create using CREATE_NEW, returns handle and error code. + ~~~ + auto [handle, error] = wil::try_create_new_file(filePath.c_str()); + ~~~ + */ + inline file_and_error_result try_create_new_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) noexcept + { + return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + } -/** create using TRUNCATE_EXISTING, returns handle and error code. -~~~ -auto [handle, error] = wil::try_truncate_existing_file(filePath.c_str()); -~~~ -*/ -inline file_and_error_result try_truncate_existing_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) noexcept -{ - return details::create_file( - path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); -} + /** create using OPEN_ALWAYS, returns handle and error code. + ~~~ + auto [handle, error] = wil::try_open_or_create_file(filePath.c_str()); + ~~~ + */ + inline file_and_error_result try_open_or_create_file(PCWSTR path, + DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) noexcept + { + return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + } -/** create using CREATE_NEW, returns the file handle, throws on error. -~~~ -auto handle = wil::create_new_file(filePath.c_str()); -~~~ -*/ -inline wil::unique_hfile create_new_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) -{ - auto result = try_create_new_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); - THROW_WIN32_IF(result.last_error, !result.file.is_valid()); - return wistd::move(result.file); -} + /** create using CREATE_ALWAYS, returns handle and error code. + ~~~ + auto [handle, error] = wil::try_open_or_truncate_existing_file(filePath.c_str()); + ~~~ + */ + inline file_and_error_result try_open_or_truncate_existing_file( + PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) noexcept + { + return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + } -/** create using OPEN_ALWAYS, returns the file handle, throws on error. -~~~ -auto handle = wil::open_or_create_file(filePath.c_str()); -~~~ -*/ -inline wil::unique_hfile open_or_create_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) -{ - auto result = try_open_or_create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); - THROW_WIN32_IF(result.last_error, !result.file.is_valid()); - return wistd::move(result.file); -} + /** create using TRUNCATE_EXISTING, returns handle and error code. + ~~~ + auto [handle, error] = wil::try_truncate_existing_file(filePath.c_str()); + ~~~ + */ + inline file_and_error_result try_truncate_existing_file( + PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, HANDLE hTemplateFile = nullptr) noexcept + { + return details::create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + } -/** create using CREATE_ALWAYS, returns the file handle, throws on error. -~~~ -auto handle = wil::open_or_truncate_existing_file(filePath.c_str()); -~~~ -*/ -inline wil::unique_hfile open_or_truncate_existing_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) -{ - auto result = try_open_or_truncate_existing_file( - path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); - THROW_WIN32_IF(result.last_error, !result.file.is_valid()); - return wistd::move(result.file); -} + /** create using CREATE_NEW, returns the file handle, throws on error. + ~~~ + auto handle = wil::create_new_file(filePath.c_str()); + ~~~ + */ + inline wil::unique_hfile create_new_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) + { + auto result = try_create_new_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + THROW_WIN32_IF(result.last_error, !result.file.is_valid()); + return wistd::move(result.file); + } -/** create using TRUNCATE_EXISTING, returns the file handle, throws on error. -~~~ -auto handle = wil::truncate_existing_file(filePath.c_str()); -~~~ -*/ -inline wil::unique_hfile truncate_existing_file( - PCWSTR path, - DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, - DWORD dwShareMode = FILE_SHARE_READ, - LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, - DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, - HANDLE hTemplateFile = nullptr) -{ - auto result = - try_truncate_existing_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwFlagsAndAttributes, hTemplateFile); - THROW_WIN32_IF(result.last_error, !result.file.is_valid()); - return wistd::move(result.file); -} + /** create using OPEN_ALWAYS, returns the file handle, throws on error. + ~~~ + auto handle = wil::open_or_create_file(filePath.c_str()); + ~~~ + */ + inline wil::unique_hfile open_or_create_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) + { + auto result = try_open_or_create_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + THROW_WIN32_IF(result.last_error, !result.file.is_valid()); + return wistd::move(result.file); + } + + /** create using CREATE_ALWAYS, returns the file handle, throws on error. + ~~~ + auto handle = wil::open_or_truncate_existing_file(filePath.c_str()); + ~~~ + */ + inline wil::unique_hfile open_or_truncate_existing_file(PCWSTR path, + DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) + { + auto result = try_open_or_truncate_existing_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + THROW_WIN32_IF(result.last_error, !result.file.is_valid()); + return wistd::move(result.file); + } + + /** create using TRUNCATE_EXISTING, returns the file handle, throws on error. + ~~~ + auto handle = wil::truncate_existing_file(filePath.c_str()); + ~~~ + */ + inline wil::unique_hfile truncate_existing_file(PCWSTR path, DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, + DWORD dwShareMode = FILE_SHARE_READ, + LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, + DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, + HANDLE hTemplateFile = nullptr) + { + auto result = try_truncate_existing_file(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwFlagsAndAttributes, hTemplateFile); + THROW_WIN32_IF(result.last_error, !result.file.is_valid()); + return wistd::move(result.file); + } #endif // WIL_ENABLE_EXCEPTIONS #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) } // namespace wil #ifndef WIL_NO_FILE_TYPE_OPERATORS -inline bool operator==(const FILE_ID_128& left, const FILE_ID_128& right) +inline bool operator==(const FILE_ID_128 &left, const FILE_ID_128 &right) { return memcmp(&left, &right, sizeof(left)) == 0; } -inline bool operator!=(const FILE_ID_128& left, const FILE_ID_128& right) +inline bool operator!=(const FILE_ID_128 &left, const FILE_ID_128 &right) { return !operator==(left, right); } diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/nt_result_macros.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/nt_result_macros.h index efcf4af..3b6282e 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/nt_result_macros.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/nt_result_macros.h @@ -9,8 +9,8 @@ // //********************************************************* //! @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. +//! 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 @@ -18,27 +18,27 @@ // 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; \ - } \ +#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; \ - } \ +#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 @@ -50,31 +50,31 @@ #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, ...) \ +#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); \ - } \ - } \ +#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__); \ - } \ - } \ +#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) //***************************************************************************** @@ -83,150 +83,163 @@ // 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, ...) \ +#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() \ + catch (...) \ + { \ + NT_RETURN_CAUGHT_EXCEPTION(); \ } -#define NT_CATCH_RETURN_MSG(fmt, ...) \ - catch (...) \ - { \ - NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ +#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 -//***************************************************************************** + //***************************************************************************** + // 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) + // 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 { - status = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).status; - } - if (FAILED_NTSTATUS(status)) - { - return status; + 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)); } - // 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 - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException( - __R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg( - __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList); - - namespace __R_NS_NAME + /// @cond + namespace details { + template + __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException( + __R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); + template + __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(__R_DIRECT_FN_CALL_ONLY); - } + __R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportStatus_CaughtException(__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(__R_DIRECT_FN_CALL formatString, argList); - } + __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( + __R_DIRECT_FN_CALL formatString, argList); + } #endif - } // namespace __R_NS_NAME + } // namespace __R_NS_NAME - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status; - } + template + __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, + SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported) + .status; + } - template <> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - RESULT_NORETURN_RESULT( - ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status); - } + template <> + __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException( + __R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), supported) + .status); + } - template <> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - RESULT_NORETURN_RESULT( - ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status); - } + template <> + __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException( + __R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), supported) + .status); + } - template - __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(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status; - } + template + __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(__R_FN_CALL_FULL, message, ARRAYSIZE(message), + SupportedExceptions::Default) + .status; + } - template <> - __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" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( - __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) - .status); - } + template <> + __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" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) + .status); + } - template <> - __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" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( - __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) - .status); - } -} // namespace details -/// @endcond + template <> + __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" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) + .status); + } + } // namespace details + /// @endcond } // namespace wil #endif // __WIL_NT_RESULTMACROS_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry.h index ab2ad14..f3b454a 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry.h @@ -17,10 +17,10 @@ #error This header is not supported in kernel-mode. #endif -#include -#include // new(std::nothrow) #include "registry_helpers.h" #include "resource.h" +#include // new(std::nothrow) +#include // wil registry does not require the use of the STL or C++ exceptions (see _nothrow functions) // wil registry natively supports std::vector and std::wstring when preferring those types @@ -28,3295 +28,3491 @@ namespace wil { -//! Functions and classes that support reading and writing values to/from the registry. -namespace reg -{ + //! Functions and classes that support reading and writing values to/from the registry. + namespace reg + { #if defined(WIL_ENABLE_EXCEPTIONS) - /** - * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * @param key An open or well-known registry key - * @param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * @param access The requested access desired for the opened key - * @return A wil::unique_hkey containing the resulting opened HKEY - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::unique_hkey open_unique_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{key}; - ::wil::unique_hkey return_value; - regview.open_key(subKey, &return_value, access); - return return_value; - } + /** + * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW + * @param key An open or well-known registry key + * @param subKey The name of the registry subkey to be opened. + * If `nullptr`, then `key` is used without modification. + * @param access The requested access desired for the opened key + * @return A wil::unique_hkey containing the resulting opened HKEY + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline ::wil::unique_hkey open_unique_key(HKEY key, _In_opt_ PCWSTR subKey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + { + const reg_view_details::reg_view regview{key}; + ::wil::unique_hkey return_value; + regview.open_key(subKey, &return_value, access); + return return_value; + } - /** - * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * @param key An open or well-known registry key - * @param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * @param access The requested access desired for the opened key - * @return A wil::unique_hkey or wil::shared_hkey containing the resulting opened HKEY - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::unique_hkey create_unique_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{key}; - ::wil::unique_hkey return_value; - regview.create_key(subKey, &return_value, access); - return return_value; - } + /** + * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW + * @param key An open or well-known registry key + * @param subKey The name of a subkey that this function opens or creates. + * Note: this cannot be null (see the above referenced API documentation) + * @param access The requested access desired for the opened key + * @return A wil::unique_hkey or wil::shared_hkey containing the resulting opened HKEY + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline ::wil::unique_hkey create_unique_key(HKEY key, PCWSTR subKey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + { + const reg_view_details::reg_view regview{key}; + ::wil::unique_hkey return_value; + regview.create_key(subKey, &return_value, access); + return return_value; + } #if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN) - /** - * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * @param key An open or well-known registry key - * @param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * @param access The requested access desired for the opened key - * @return A wil::shared_hkey containing the resulting opened HKEY - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::shared_hkey open_shared_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{key}; - ::wil::shared_hkey return_value; - regview.open_key(subKey, &return_value, access); - return return_value; - } + /** + * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW + * @param key An open or well-known registry key + * @param subKey The name of the registry subkey to be opened. + * If `nullptr`, then `key` is used without modification. + * @param access The requested access desired for the opened key + * @return A wil::shared_hkey containing the resulting opened HKEY + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline ::wil::shared_hkey open_shared_key(HKEY key, _In_opt_ PCWSTR subKey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + { + const reg_view_details::reg_view regview{key}; + ::wil::shared_hkey return_value; + regview.open_key(subKey, &return_value, access); + return return_value; + } - /** - * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * @param key An open or well-known registry key - * @param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * @param access The requested access desired for the opened key - * @return A wil::shared_hkey or wil::shared_hkey containing the resulting opened HKEY - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::shared_hkey create_shared_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{key}; - ::wil::shared_hkey return_value; - regview.create_key(subKey, &return_value, access); - return return_value; - } + /** + * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW + * @param key An open or well-known registry key + * @param subKey The name of a subkey that this function opens or creates. + * Note: this cannot be null (see the above referenced API documentation) + * @param access The requested access desired for the opened key + * @return A wil::shared_hkey or wil::shared_hkey containing the resulting opened HKEY + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline ::wil::shared_hkey create_shared_key(HKEY key, PCWSTR subKey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + { + const reg_view_details::reg_view regview{key}; + ::wil::shared_hkey return_value; + regview.create_key(subKey, &return_value, access); + return return_value; + } #endif // #if defined(__WIL_WINREG_STL) #endif // #if defined(WIL_ENABLE_EXCEPTIONS) - /** - * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * @param key An open or well-known registry key - * @param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY - * @param access The requested access desired for the opened key - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT open_unique_key_nothrow( - HKEY key, _In_opt_ PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.open_key(subKey, hkey.put(), access); - } - - /** - * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * @param key An open or well-known registry key - * @param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY - * @param access The requested access desired for the opened key - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT create_unique_key_nothrow( - HKEY key, PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.create_key(subKey, hkey.put(), access); - } - -#if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN) - /** - * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * @param key An open or well-known registry key - * @param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY - * @param access The requested access desired for the opened key - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT open_shared_key_nothrow( - HKEY key, _In_opt_ PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.open_key(subKey, hkey.put(), access); - } - - /** - * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * @param key An open or well-known registry key - * @param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY - * @param access The requested access desired for the opened key - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT create_shared_key_nothrow( - HKEY key, PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.create_key(subKey, hkey.put(), access); - } -#endif // #define __WIL_WINREG_STL - - // - // wil::key_iterator and wil::value_iterator objects enable enumerating registry keys and values. - // - // Examples of usage when std::wstring is included: - // - // for (const auto& key_data : wil::make_range(wil::reg::key_iterator{hkey}, wil::reg::key_iterator{})) - // { - // key_data.name; // the std::wstring of the enumerated key - // } - // - // for (const auto& value_data : wil::make_range(wil::reg::value_iterator{hkey}, wil::reg::value_iterator{})) - // { - // value_data.name; // the std::wstring of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // - // When std::wstring is not included, wil::unique_process_heap_string can be used instead: - // - // for (const auto& key_data : wil::make_range(wil::reg::key_heap_string_iterator{hkey}, wil::reg::key_heap_string_iterator{})) - // { - // key_data.name.get(); // the PCWSTR of the enumerated key - // } - // - // for (const auto& value_data : wil::make_range(wil::reg::value_heap_string_iterator{hkey}, wil::reg::value_heap_string_iterator{})) - // { - // value_data.name.get(); // the PCWSTR of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // - // When not using exceptions, can manually walk the iterator using wil::unique_process_heap_string: - // - // auto iterate_keys = wil::reg::key_heap_string_nothrow_iterator{hkey}; - // for (const auto& key_data : wil::make_range(iterate_keys, wil::reg::key_heap_string_nothrow_iterator{})) - // { - // key_data.name.get(); // the PCWSTR of the enumerated key - // } - // if (FAILED(iterate_keys.last_error())) - // { - // // the HRESULT last_error() returns the registry error that prevented enumeration - // } - // - // auto iterate_values = wil::reg::value_heap_string_nothrow_iterator{hkey}; - // for (const auto& value_data : wil::make_range(iterate_values, wil::reg::value_heap_string_nothrow_iterator{})) - // { - // value_data.name.get(); // the PCWSTR of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // if (FAILED(iterate_values.last_error())) - // { - // // the HRESULT last_error() returns the registry error that prevented enumeration - // } - // -#if defined(WIL_ENABLE_EXCEPTIONS) - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - using key_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::std::wstring>>; - using value_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::std::wstring>>; -#endif - -#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) - using key_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; - using value_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; -#endif // #if defined(__WIL_OLEAUTO_H_) - - using key_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; - using value_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; - -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - - // no-throw versions of applicable registry iterators -#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) - using key_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; - using value_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; -#endif // #if defined(__WIL_OLEAUTO_H_) - - using key_heap_string_nothrow_iterator = - ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; - using value_heap_string_nothrow_iterator = - ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; - - /** - * @brief Queries for number of sub-keys - * @param key The HKEY to query for number of sub-keys - * @param[out] numSubKeys A pointer to a DWORD to receive the returned count - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ DWORD* numSubKeys) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class character count, - nullptr, // null reserved - numSubKeys, - nullptr, // null max subkey length - nullptr, // null max class length - nullptr, // null value count - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - nullptr)); // null last write filetime - return S_OK; - } - - inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ uint32_t* numSubKeys) WI_NOEXCEPT - { - DWORD subKeys{}; - RETURN_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &subKeys)); - *numSubKeys = subKeys; - return S_OK; - } - - /** - * @brief Queries for number of values - * @param key The HKEY to query for number of values - * @param[out] numSubValues A pointer to a DWORD to receive the returned count - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ DWORD* numSubValues) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class char count, - nullptr, // null reserved - nullptr, // null subkey count - nullptr, // null max subkey length - nullptr, // null max class length - numSubValues, - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - nullptr)); // null last write filetime - return S_OK; - } - - inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ uint32_t* numSubValues) WI_NOEXCEPT - { - DWORD subValues{}; - RETURN_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &subValues)); - *numSubValues = subValues; - return S_OK; - } - - /** - * @brief Queries for the filetime when the registry key was last written - * @param key The HKEY to query for number of values - * @param[out] lastModified A pointer to a FILETIME to receive the last write time - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline HRESULT get_last_write_filetime_nothrow(HKEY key, _Out_ FILETIME* lastModified) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class char count, - nullptr, // null reserved - nullptr, // null subkey count - nullptr, // null max subkey length - nullptr, // null max class length - nullptr, // null value count - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - lastModified)); - return S_OK; - } - -#if defined(WIL_ENABLE_EXCEPTIONS) - /** - * @brief Queries for number of sub-keys - * @param key The HKEY to query for number of sub-keys - * @return The queried number of sub-keys if succeeded - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline uint32_t get_child_key_count(HKEY key) - { - uint32_t numSubKeys{}; - THROW_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &numSubKeys)); - return numSubKeys; - } - - /** - * @brief Queries for number of values - * @param key The HKEY to query for number of values - * @return The queried number of value if succeeded - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline uint32_t get_child_value_count(HKEY key) - { - uint32_t numSubValues{}; - THROW_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &numSubValues)); - return numSubValues; - } - - /** - * @brief Queries for the filetime when the registry key was last written - * @param key The HKEY to query for number of values - * @return The queried filetime if succeeded - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline FILETIME get_last_write_filetime(HKEY key) - { - FILETIME lastModified{}; - THROW_IF_FAILED(::wil::reg::get_last_write_filetime_nothrow(key, &lastModified)); - return lastModified; - } -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(WIL_ENABLE_EXCEPTIONS) - // - // template - // void set_value(...) - // - // - Writes a value to a specified key and subkey, deducing the type from the given data - // - Throws a std::exception on failure (including wil::ResultException) - // - // Examples of usage (the template type does not need to be explicitly specified) - // wil::reg::set_value(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD - // wil::reg::set_value(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD - // wil::reg::set_value(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // wil::reg::set_value(key, L"dword_value_name", 0); // writes a REG_DWORD - // wil::reg::set_value(key, L"qword_value_name", 0ull); // writes a REG_QWORD - // wil::reg::set_value(key, L"string_value_name", L"hello"); // writes a REG_SZ - // - // Example usage writing a vector of wstrings to a REG_MULTI_SZ - // std::vector data { L"string1", L"string2", L"string3" }; - // wil::reg::set_value(key, L"multi_string_value_name", data); - // wil::reg::set_value(key, L"multi_string_value_name", data); - // - // Example of usage writing directly to a registry value from a raw byte vector - // - notice the registry type is required, not implied - // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; - // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); - // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); - // - - /** - * @brief Writes a value to a specified key and subkey, deducing the type from the given data. - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The data (of type T) to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - template - void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) - { - const reg_view_details::reg_view regview{key}; - regview.set_value(subkey, value_name, data); - } - - /** - * @brief Writes a value under a specified key, the registry type based off the templated type passed as data - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The data (of type T) to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - template - void set_value(HKEY key, _In_opt_ PCWSTR value_name, const T& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a null-terminated string value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - const reg_view_details::reg_view regview{key}; - regview.set_value(subkey, value_name, data); - } - - /** - * @brief Writes a null-terminated string value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_DWORD value from a uint32_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 32-bit value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_DWORD value from a uint32_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 32-bit value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_dword(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_QWORD value from a uint64_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 64-bit value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_QWORD value from a uint64_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 64-bit value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_qword(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_EXPAND_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - const reg_view_details::reg_view regview{key}; - regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); - } - - /** - * @brief Writes a REG_EXPAND_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value_expanded_string(key, nullptr, value_name, data); - } - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - const auto multiStringWcharVector(reg_view_details::get_multistring_from_wstrings(::std::begin(data), ::std::end(data))); - const reg_view_details::reg_view regview{key}; - regview.set_value(subkey, value_name, multiStringWcharVector, REG_MULTI_SZ); - } - - /** - * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_MULTI_SZ value from a std::vector - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_MULTI_SZ value from a std::vector - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } -#endif - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param type The registry type for the specified registry value - see RegSetKeyValueW - * @param data A `std::vector`/`std::vector` to write to the specified registry value. - * The vector contents will be directly marshaled to the specified value. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) - { - const reg_view_details::reg_view regview{key}; - regview.set_value(subkey, value_name, data, type); - } - - /** - * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param type The registry type for the specified registry value - see RegSetKeyValueW - * @param data A `std::vector`/`std::vector` to write to the specified registry value. - * The vector contents will be directly marshaled to the specified value. - * @exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) - { - ::wil::reg::set_value_binary(key, nullptr, value_name, type, data); - } -#endif -#endif - - // - // template - // HRESULT set_value_nothrow(...) - // - // - Writes a value under a specified key - // - The type of registry value is determined by the template type T of data given - // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) - // - // Examples of usage (the template type does not need to be explicitly specified) - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // hr = wil::reg::set_value_nothrow(key, L"dword_value_name", 0); // writes a REG_DWORD - // hr = wil::reg::set_value_nothrow(key, L"qword_value_name", 0ull); // writes a REG_QWORD - // hr = wil::reg::set_value_nothrow(key, L"string_value_name", L"hello"); // writes a REG_SZ - // - // Example of usage writing a REG_MULTI_SZ - // std::vector multisz_data { L"string1", L"string2", L"string3" }; - // hr = wil::reg::set_value_nothrow(key, L"multi_string_value_name", multisz_data); - // - // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: - // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; - // hr = wil::reg::set_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, data); - // - /** - * @brief Writes a value to a specified key and subkey, deducing the type from the given data. - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The data (of type T) to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.set_value(subkey, value_name, data); - } - - /** - * @brief Writes a value under a specified key, the registry type based off the templated type passed as data - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The data (of type T) to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * @brief Writes a null-terminated string value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.set_value(subkey, value_name, data); - } - - /** - * @brief Writes a null-terminated string value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_DWORD value from a uint32_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 32-bit value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_DWORD value from a uint32_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 32-bit value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_QWORD value from a uint64_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 64-bit value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_QWORD value from a uint64_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The 64-bit value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * @brief Writes a REG_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * @brief Writes a REG_EXPAND_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); - } - - /** - * @brief Writes a REG_EXPAND_SZ value from a null-terminated string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param data The null-terminated string value to write to the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_expanded_string_nothrow(key, nullptr, value_name, data); - } - -#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Writes raw bytes into a registry value under a specified key of the specified type - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param type The registry type for the specified registry value to write to - see RegSetValue - * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_binary_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - RETURN_IF_FAILED(regview.set_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, value, type)); - return S_OK; - } - - /** - * @brief Writes raw bytes into a registry value under a specified key of the specified type - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * @param type The registry type for the specified registry value to write to - see RegSetValue - * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_binary_nothrow( - HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return ::wil::reg::set_value_binary_nothrow(key, nullptr, value_name, type, value); - } -#endif - -#if defined(WIL_ENABLE_EXCEPTIONS) - // - // template - // T get_value(...) - // - // - Reads a value under a specified key. - // - Requires a type T to be specified. - // - Throws a std::exception on failure (including wil::ResultException), including registry value not found. - // If you don't want an exception when the value does not exist, use try_get_value(...) - // - // Examples of usage (ensure the code handles a possible std::exception that will be thrown on all errors) - // uint32_t dword_value = wil::reg::get_value(key, L"subkey", L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value(key, L"subkey", L"qword_value_name); - // std::wstring string_value = wil::reg::get_value(key, L"subkey", L"string_value_name"); - // - // A subkey is not required if the key is opened where this should write the value: - // uint32_t dword_value = wil::reg::get_value(key, L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value(key, L"qword_value_name); - // std::wstring string_value = wil::reg::get_value(key, L"string_value_name"); - // - // The template type does not need to be specified if using functions written for a targeted type - // uint32_t dword_value = wil::reg::get_value_dword(key, L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value_qword(key, L"qword_value_name"); - // std::wstring string_value = wil::reg::get_value_string(key, L"string_value_name"); - // - // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: - // std::wstring expanded_string_value = wil::reg::get_value_expanded_string(key, L"string_value_name_with_environment_variables"); - // - // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: - // std::vector data = wil::reg::get_value_binary(key, L"binary_value_name", REG_BINARY); - // - // Multi-string values can be read into a vector; e.g.: - // std::vector multi_string_value = wil::reg::get_value_multistring(key, L"multi_string_value_name"); - // for (const auto& sub_string_value : multi_string_value) - // { - // // can read each string parsed from the multi-string - // PCWSTR string_value = sub_string_value.c_str(); - // } - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string and get_value_expanded_string functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Reading a bstr can be stored in a wil::shared_bstr or wil::unique_bstr - wil::shared_bstr has a c'tor taking a wil::unique_bstr - // wil::unique_bstr unique_value { wil::reg::get_value_string<::wil::unique_bstr>(key, L"string_value_name") }; - // wil::shared_bstr shared_value { wil::reg::get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; - // - // Reading a cotaskmem string can be stored in a wil::unique_cotaskmem_string or wil::shared_cotaskmem_string - // wil::unique_cotaskmem_string unique_value { wil::reg::get_value_string(key, L"string_value_name") }; - // wil::shared_cotaskmem_string shared_value { wil::reg::get_value_string(key, L"string_value_name") }; - // - // Blocking get_value_string template types that are not already specialized - this gives a much friendlier compiler error message - template - T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); - } - - template - T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); - } - - template - T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); - } - - template - T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); - } - - /** - * @brief Reads a value from a specified key and subkey, deducing registry type from the type parameter T. - * @tparam T The type to read (the registry value type is deduced from T) - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type T - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template - T get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - T return_value{}; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, return_value); - return return_value; - } - - /** - * @brief Reads a value under a specified key, deducing registry type from the type parameter T. - * @tparam T The type to read (the registry value type is deduced from T) - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type T - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template - T get_value(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_DWORD value, returning a uint32_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The uint32_t value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, subkey, value_name); - } - - /** - * @brief Reads a REG_DWORD value, returning a uint32_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The uint32_t value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_QWORD value, returning a uint64_t - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The uint64_t value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, subkey, value_name); - } - - /** - * @brief Reads a REG_QWORD value, returning a uint64_t - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The uint64_t value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::wstring value; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, subkey, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); - } -#endif - -#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value, returning a wil::unique_bstr - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_bstr created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_bstr>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a wil::unique_bstr - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_bstr created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_bstr>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::unique_bstr value; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string<::wil::unique_bstr>(key, nullptr, value_name); - } - -#if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value, returning a wil::shared_bstr - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_bstr created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_bstr>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a wil::shared_bstr - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_bstr created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_bstr>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::shared_bstr value; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_bstr - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_cotaskmem_string created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_cotaskmem_string created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::unique_cotaskmem_string value; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::unique_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return wil::reg::get_value_expanded_string<::wil::unique_cotaskmem_string>(key, nullptr, value_name); - } - -#if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_cotaskmem_string created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_cotaskmem_string created from the string value read from the registry - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::shared_cotaskmem_string value; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A wil::shared_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return wil::reg::get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OBJBASE_H_STL) -#endif // defined(__WIL_OBJBASE_H_) - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Reads a registry value of the specified type, returning a std::vector - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @return A std::vector containing the bytes of the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) - { - ::std::vector return_value{}; - const reg_view_details::reg_view regview{key}; - regview.get_value(subkey, value_name, return_value, type); - return return_value; - } - - /** - * @brief Reads a registry value of the specified type, returning a std::vector - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @return A std::vector containing the bytes of the specified registry value - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) - { - return ::wil::reg::get_value_binary(key, nullptr, value_name, type); - } -#endif - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_MULTI_SZ value, returning a std::vector - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - template <> - inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::vector<::std::wstring> return_value; - ::std::vector rawData{::wil::reg::get_value_binary(key, subkey, value_name, REG_MULTI_SZ)}; - if (!rawData.empty()) + /** + * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW + * @param key An open or well-known registry key + * @param subKey The name of the registry subkey to be opened. + * If `nullptr`, then `key` is used without modification. + * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY + * @param access The requested access desired for the opened key + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT open_unique_key_nothrow(HKEY key, _In_opt_ PCWSTR subKey, ::wil::unique_hkey &hkey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT { - auto* const begin = reinterpret_cast(rawData.data()); - auto* const end = begin + rawData.size() / sizeof(wchar_t); - return_value = ::wil::reg::reg_view_details::get_wstring_vector_from_multistring(begin, end); + const reg_view_details::reg_view_nothrow regview{key}; + return regview.open_key(subKey, hkey.put(), access); } - return return_value; - } - - /** - * @brief Reads a REG_MULTI_SZ value, returning a std::vector - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - template <> - inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } - - /** - * @brief Reads a REG_MULTI_SZ value, returning a std::vector - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, subkey, value_name); - } - - /** - * @brief Reads a REG_MULTI_SZ value, returning a std::vector - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } -#endif - -#if (WIL_USE_STL && (__cpp_lib_optional >= 201606L)) || defined(WIL_DOXYGEN) - // - // template - // void try_get_value(...) - // - // - Reads a value under a specified key and subkey, deducing registry type from the type parameter T. - // - throws a std::exception on failure (including wil::ResultException), except if the registry value was not found - // returns a std::nullopt if the registry value is not found - // - // Examples using the returned std::optional - // - Caller should ensure the code handles a possible std::exception that will be thrown on all errors except value not found - // - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); - // if (opt_dword_value.has_value()) - // { - // // opt_dword_value.value() returns the uint32_t read from the registry - // } - // else - // { - // // the registry value did not exist - // } - // // if the caller wants to apply a default value of 0, they can call value_or() - // uint32_t opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name").value_or(0); - // - // Examples using the returned std::optional - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); - // if (opt_string_value.has_value()) - // { - // // opt_string_value.value() returns the std::wstring read from the registry - // // the below avoids copying the std::wstring as value() here returns a std::wstring& - // PCWSTR string_value = opt_string_value.value().c_str(); - // } - // else - // { - // // the registry value did not exist - // } - // - // // if the caller wants to apply a default value of L"default", they can call value_or() - // // note that std::optional only attempts to construct a std::wstring for L"default" if the std::optional is empty (std::nullopt) - // // thus only allocating a new std::wstring for the default value when it's needed - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name").value_or(L"default"); - // - // Examples of usage: - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"subkey", L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value(key, L"subkey", L"qword_value_name); - // std::optional opt_string_value = wil::reg::try_get_value(key, L"subkey", L"string_value_name"); - // - // A subkey is not required if the key is opened where this should write the value; e.g. - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value(key, L"qword_value_name); - // std::optional opt_string_value = wil::reg::try_get_value(key, L"string_value_name"); - // - // The template type does not need to be specified if using functions written for a targeted type; e.g. - // std::optional opt_dword_value = wil::reg::try_get_value_dword(key, L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value_qword(key, L"qword_value_name"); - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); - // - // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: - // std::optional opt_expanded_string_value = wil::reg::try_get_value_expanded_string(key, L"string_value_name_with_environment_variables"); - // - // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: - // std::optional> opt_data = wil::reg::try_get_value_binary(key, L"binary_value_name", REG_BINARY); - // - // Multi-string values can be read into a std::vector; e.g.: - // std::optional<::std::vector<::std::wstring>> try_get_value_multistring(key, L"multi_string_value_name"); - // See the definition of try_get_value_multistring before for usage guidance - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated try_get_value_string and try_get_value_expanded_string functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Reading a bstr is returned in a std::optional - because wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - // std::optional shared_value { wil::reg::try_get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; - // - // Reading a cotaskmem string is returned in a std::optional - because wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - // std::optional opt_shared_value { wil::reg::try_get_value_string(key, L"string_value_name") }; - // - // Blocking try_get_value_string template types that are not already specialized - this gives a much friendlier compiler error message - template - ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); - } - - template - ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); - } - - template - ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); - } - - template - ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); - } - - /** - * @brief Attempts to read a value under a specified key and subkey, returning in a std::optional, deducing registry type from - * the type parameter T. - * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value (of type T) read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template - ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { -#if defined(__WIL_OLEAUTO_H_) - // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); -#endif // #if defined(__WIL_OLEAUTO_H_) -#if defined(__WIL_OBJBASE_H_) - // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); -#endif // #if defined(__WIL_OBJBASE_H_) - - const reg_view_details::reg_view regview{key}; - return regview.try_get_value(subkey, value_name); - } - - /** - * @brief Attempts to read a value under a specified key, returning the value in a std::optional, deducing registry type from - * the type parameter T. - * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value (of type T) read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template - ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR value_name) - { -#if defined(__WIL_OLEAUTO_H_) - // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); -#endif // #if defined(__WIL_OLEAUTO_H_) -#if defined(__WIL_OBJBASE_H_) - // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); -#endif // #if defined(__WIL_OBJBASE_H_) - - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, subkey, value_name); - } - - /** - * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, subkey, value_name); - } - - /** - * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a - * std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @return The raw bytes read from the registry value stored in a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::std::vector>(subkey, value_name, type); - } - - /** - * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a - * std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @return The raw bytes read from the registry value stored in a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) - { - return ::wil::reg::try_get_value_binary(key, nullptr, value_name, type); - } -#endif - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::std::wstring>(subkey, value_name); - } - - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, subkey, value_name); - } - - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::std::wstring>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, subkey, value_name); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); - } -#endif - -#if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::wil::shared_bstr>(subkey, value_name); - } - - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string<::wil::shared_bstr>(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::wil::shared_bstr>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) - -#if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name); - } - - /** - * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional<:wil::shared_cotaskmem_string>, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{key}; - return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>( - HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } -#endif // defined(__WIL_OBJBASE_H_STL) - -#if WIL_USE_STL || defined(WIL_DOXYGEN) - /** - * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::vector<::std::wstring> value; - const auto hr = ::wil::ResultFromException([&] { - value = ::wil::reg::get_value_multistring(key, subkey, value_name); - }); - if (SUCCEEDED(hr)) + /** + * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW + * @param key An open or well-known registry key + * @param subKey The name of a subkey that this function opens or creates. + * Note: this cannot be null (see the above referenced API documentation) + * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY + * @param access The requested access desired for the opened key + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT create_unique_key_nothrow(HKEY key, PCWSTR subKey, ::wil::unique_hkey &hkey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + WI_NOEXCEPT { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.create_key(subKey, hkey.put(), access); + } + +#if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN) + /** + * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW + * @param key An open or well-known registry key + * @param subKey The name of the registry subkey to be opened. + * If `nullptr`, then `key` is used without modification. + * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY + * @param access The requested access desired for the opened key + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT open_shared_key_nothrow(HKEY key, _In_opt_ PCWSTR subKey, ::wil::shared_hkey &hkey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.open_key(subKey, hkey.put(), access); + } + + /** + * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW + * @param key An open or well-known registry key + * @param subKey The name of a subkey that this function opens or creates. + * Note: this cannot be null (see the above referenced API documentation) + * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY + * @param access The requested access desired for the opened key + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT create_shared_key_nothrow(HKEY key, PCWSTR subKey, ::wil::shared_hkey &hkey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) + WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.create_key(subKey, hkey.put(), access); + } +#endif // #define __WIL_WINREG_STL + + // + // wil::key_iterator and wil::value_iterator objects enable enumerating registry keys and values. + // + // Examples of usage when std::wstring is included: + // + // for (const auto& key_data : wil::make_range(wil::reg::key_iterator{hkey}, wil::reg::key_iterator{})) + // { + // key_data.name; // the std::wstring of the enumerated key + // } + // + // for (const auto& value_data : wil::make_range(wil::reg::value_iterator{hkey}, + // wil::reg::value_iterator{})) + // { + // value_data.name; // the std::wstring of the enumerated value + // value_data.type; // the REG_ type of the enumerated value + // } + // + // When std::wstring is not included, wil::unique_process_heap_string can be used instead: + // + // for (const auto& key_data : wil::make_range(wil::reg::key_heap_string_iterator{hkey}, + // wil::reg::key_heap_string_iterator{})) + // { + // key_data.name.get(); // the PCWSTR of the enumerated key + // } + // + // for (const auto& value_data : wil::make_range(wil::reg::value_heap_string_iterator{hkey}, + // wil::reg::value_heap_string_iterator{})) + // { + // value_data.name.get(); // the PCWSTR of the enumerated value + // value_data.type; // the REG_ type of the enumerated value + // } + // + // When not using exceptions, can manually walk the iterator using wil::unique_process_heap_string: + // + // auto iterate_keys = wil::reg::key_heap_string_nothrow_iterator{hkey}; + // for (const auto& key_data : wil::make_range(iterate_keys, wil::reg::key_heap_string_nothrow_iterator{})) + // { + // key_data.name.get(); // the PCWSTR of the enumerated key + // } + // if (FAILED(iterate_keys.last_error())) + // { + // // the HRESULT last_error() returns the registry error that prevented enumeration + // } + // + // auto iterate_values = wil::reg::value_heap_string_nothrow_iterator{hkey}; + // for (const auto& value_data : wil::make_range(iterate_values, + // wil::reg::value_heap_string_nothrow_iterator{})) + // { + // value_data.name.get(); // the PCWSTR of the enumerated value + // value_data.type; // the REG_ type of the enumerated value + // } + // if (FAILED(iterate_values.last_error())) + // { + // // the HRESULT last_error() returns the registry error that prevented enumeration + // } + // +#if defined(WIL_ENABLE_EXCEPTIONS) + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + using key_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::std::wstring>>; + using value_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::std::wstring>>; +#endif + +#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) + using key_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; + using value_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; +#endif // #if defined(__WIL_OLEAUTO_H_) + + using key_heap_string_iterator = + ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; + using value_heap_string_iterator = + ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; + +#endif // #if defined(WIL_ENABLE_EXCEPTIONS) + + // no-throw versions of applicable registry iterators +#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) + using key_bstr_nothrow_iterator = + ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; + using value_bstr_nothrow_iterator = + ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; +#endif // #if defined(__WIL_OLEAUTO_H_) + + using key_heap_string_nothrow_iterator = + ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; + using value_heap_string_nothrow_iterator = + ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; + + /** + * @brief Queries for number of sub-keys + * @param key The HKEY to query for number of sub-keys + * @param[out] numSubKeys A pointer to a DWORD to receive the returned count + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ DWORD *numSubKeys) WI_NOEXCEPT + { + RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW(key, + nullptr, // null class + nullptr, // null class character count, + nullptr, // null reserved + numSubKeys, + nullptr, // null max subkey length + nullptr, // null max class length + nullptr, // null value count + nullptr, // null max value name length + nullptr, // null max value length + nullptr, // null security descriptor + nullptr)); // null last write filetime + return S_OK; + } + + inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ uint32_t *numSubKeys) WI_NOEXCEPT + { + DWORD subKeys{}; + RETURN_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &subKeys)); + *numSubKeys = subKeys; + return S_OK; + } + + /** + * @brief Queries for number of values + * @param key The HKEY to query for number of values + * @param[out] numSubValues A pointer to a DWORD to receive the returned count + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ DWORD *numSubValues) WI_NOEXCEPT + { + RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW(key, + nullptr, // null class + nullptr, // null class char count, + nullptr, // null reserved + nullptr, // null subkey count + nullptr, // null max subkey length + nullptr, // null max class length + numSubValues, + nullptr, // null max value name length + nullptr, // null max value length + nullptr, // null security descriptor + nullptr)); // null last write filetime + return S_OK; + } + + inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ uint32_t *numSubValues) WI_NOEXCEPT + { + DWORD subValues{}; + RETURN_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &subValues)); + *numSubValues = subValues; + return S_OK; + } + + /** + * @brief Queries for the filetime when the registry key was last written + * @param key The HKEY to query for number of values + * @param[out] lastModified A pointer to a FILETIME to receive the last write time + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline HRESULT get_last_write_filetime_nothrow(HKEY key, _Out_ FILETIME *lastModified) WI_NOEXCEPT + { + RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW(key, + nullptr, // null class + nullptr, // null class char count, + nullptr, // null reserved + nullptr, // null subkey count + nullptr, // null max subkey length + nullptr, // null max class length + nullptr, // null value count + nullptr, // null max value name length + nullptr, // null max value length + nullptr, // null security descriptor + lastModified)); + return S_OK; + } + +#if defined(WIL_ENABLE_EXCEPTIONS) + /** + * @brief Queries for number of sub-keys + * @param key The HKEY to query for number of sub-keys + * @return The queried number of sub-keys if succeeded + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline uint32_t get_child_key_count(HKEY key) + { + uint32_t numSubKeys{}; + THROW_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &numSubKeys)); + return numSubKeys; + } + + /** + * @brief Queries for number of values + * @param key The HKEY to query for number of values + * @return The queried number of value if succeeded + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline uint32_t get_child_value_count(HKEY key) + { + uint32_t numSubValues{}; + THROW_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &numSubValues)); + return numSubValues; + } + + /** + * @brief Queries for the filetime when the registry key was last written + * @param key The HKEY to query for number of values + * @return The queried filetime if succeeded + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline FILETIME get_last_write_filetime(HKEY key) + { + FILETIME lastModified{}; + THROW_IF_FAILED(::wil::reg::get_last_write_filetime_nothrow(key, &lastModified)); + return lastModified; + } +#endif // #if defined(WIL_ENABLE_EXCEPTIONS) + +#if defined(WIL_ENABLE_EXCEPTIONS) + // + // template + // void set_value(...) + // + // - Writes a value to a specified key and subkey, deducing the type from the given data + // - Throws a std::exception on failure (including wil::ResultException) + // + // Examples of usage (the template type does not need to be explicitly specified) + // wil::reg::set_value(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD + // wil::reg::set_value(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD + // wil::reg::set_value(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ + // + // A subkey is not required if the key is opened where this should write the value: + // wil::reg::set_value(key, L"dword_value_name", 0); // writes a REG_DWORD + // wil::reg::set_value(key, L"qword_value_name", 0ull); // writes a REG_QWORD + // wil::reg::set_value(key, L"string_value_name", L"hello"); // writes a REG_SZ + // + // Example usage writing a vector of wstrings to a REG_MULTI_SZ + // std::vector data { L"string1", L"string2", L"string3" }; + // wil::reg::set_value(key, L"multi_string_value_name", data); + // wil::reg::set_value(key, L"multi_string_value_name", data); + // + // Example of usage writing directly to a registry value from a raw byte vector + // - notice the registry type is required, not implied + // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; + // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); + // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); + // + + /** + * @brief Writes a value to a specified key and subkey, deducing the type from the given data. + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The data (of type T) to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + template + void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T &data) + { + const reg_view_details::reg_view regview{key}; + regview.set_value(subkey, value_name, data); + } + + /** + * @brief Writes a value under a specified key, the registry type based off the templated type passed as data + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The data (of type T) to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + template void set_value(HKEY key, _In_opt_ PCWSTR value_name, const T &data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a null-terminated string value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) + { + const reg_view_details::reg_view regview{key}; + regview.set_value(subkey, value_name, data); + } + + /** + * @brief Writes a null-terminated string value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_DWORD value from a uint32_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 32-bit value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) + { + ::wil::reg::set_value(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_DWORD value from a uint32_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 32-bit value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_dword(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_QWORD value from a uint64_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 64-bit value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) + { + ::wil::reg::set_value(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_QWORD value from a uint64_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 64-bit value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_qword(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) + { + ::wil::reg::set_value(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_EXPAND_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated, unexpanded string value to write to the specified registry value. For + * example, `%PATH%`. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) + { + const reg_view_details::reg_view regview{key}; + regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); + } + + /** + * @brief Writes a REG_EXPAND_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated, unexpanded string value to write to the specified registry value. For + * example, `%PATH%`. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) + { + ::wil::reg::set_value_expanded_string(key, nullptr, value_name, data); + } + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data A std::vector to write to the specified registry value. + * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + const ::std::vector<::std::wstring> &data) + { + const auto multiStringWcharVector( + reg_view_details::get_multistring_from_wstrings(::std::begin(data), ::std::end(data))); + const reg_view_details::reg_view regview{key}; + regview.set_value(subkey, value_name, multiStringWcharVector, REG_MULTI_SZ); + } + + /** + * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data A std::vector to write to the specified registry value. + * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring> &data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_MULTI_SZ value from a std::vector + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data A std::vector to write to the specified registry value. + * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + const ::std::vector<::std::wstring> &data) + { + ::wil::reg::set_value(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_MULTI_SZ value from a std::vector + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data A std::vector to write to the specified registry value. + * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR value_name, + const ::std::vector<::std::wstring> &data) + { + ::wil::reg::set_value(key, nullptr, value_name, data); + } +#endif + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param type The registry type for the specified registry value - see RegSetKeyValueW + * @param data A `std::vector`/`std::vector` to write to the specified registry value. + * The vector contents will be directly marshaled to the specified value. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, + const ::std::vector &data) + { + const reg_view_details::reg_view regview{key}; + regview.set_value(subkey, value_name, data, type); + } + + /** + * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param type The registry type for the specified registry value - see RegSetKeyValueW + * @param data A `std::vector`/`std::vector` to write to the specified registry value. + * The vector contents will be directly marshaled to the specified value. + * @exception std::exception (including wil::ResultException) will be thrown on all failures + */ + inline void set_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, + const ::std::vector &data) + { + ::wil::reg::set_value_binary(key, nullptr, value_name, type, data); + } +#endif +#endif + + // + // template + // HRESULT set_value_nothrow(...) + // + // - Writes a value under a specified key + // - The type of registry value is determined by the template type T of data given + // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) + // + // Examples of usage (the template type does not need to be explicitly specified) + // hr = wil::reg::set_value_nothrow(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD + // hr = wil::reg::set_value_nothrow(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD + // hr = wil::reg::set_value_nothrow(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ + // + // A subkey is not required if the key is opened where this should write the value: + // hr = wil::reg::set_value_nothrow(key, L"dword_value_name", 0); // writes a REG_DWORD + // hr = wil::reg::set_value_nothrow(key, L"qword_value_name", 0ull); // writes a REG_QWORD + // hr = wil::reg::set_value_nothrow(key, L"string_value_name", L"hello"); // writes a REG_SZ + // + // Example of usage writing a REG_MULTI_SZ + // std::vector multisz_data { L"string1", L"string2", L"string3" }; + // hr = wil::reg::set_value_nothrow(key, L"multi_string_value_name", multisz_data); + // + // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: + // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; + // hr = wil::reg::set_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, data); + // + /** + * @brief Writes a value to a specified key and subkey, deducing the type from the given data. + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The data (of type T) to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + const T &data) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.set_value(subkey, value_name, data); + } + + /** + * @brief Writes a value under a specified key, the registry type based off the templated type passed as data + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The data (of type T) to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, const T &data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); + } + + /** + * @brief Writes a null-terminated string value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + PCWSTR data) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.set_value(subkey, value_name, data); + } + + /** + * @brief Writes a null-terminated string value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_DWORD value from a uint32_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 32-bit value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + uint32_t data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_DWORD value from a uint32_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 32-bit value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_QWORD value from a uint64_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 64-bit value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + uint64_t data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_QWORD value from a uint64_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The 64-bit value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + PCWSTR data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); + } + + /** + * @brief Writes a REG_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT + { + return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); + } + + /** + * @brief Writes a REG_EXPAND_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + PCWSTR data) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); + } + + /** + * @brief Writes a REG_EXPAND_SZ value from a null-terminated string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param data The null-terminated string value to write to the specified registry value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT + { + return ::wil::reg::set_value_expanded_string_nothrow(key, nullptr, value_name, data); + } + +#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) + /** + * @brief Writes raw bytes into a registry value under a specified key of the specified type + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param type The registry type for the specified registry value to write to - see RegSetValue + * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry + * value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + uint32_t type, + const ::wil::unique_cotaskmem_array_ptr &value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + RETURN_IF_FAILED( + regview.set_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, value, type)); + return S_OK; + } + + /** + * @brief Writes raw bytes into a registry value under a specified key of the specified type + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to write to the unnamed default registry value. + * @param type The registry type for the specified registry value to write to - see RegSetValue + * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry + * value + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT set_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, + const ::wil::unique_cotaskmem_array_ptr &value) WI_NOEXCEPT + { + return ::wil::reg::set_value_binary_nothrow(key, nullptr, value_name, type, value); + } +#endif + +#if defined(WIL_ENABLE_EXCEPTIONS) + // + // template + // T get_value(...) + // + // - Reads a value under a specified key. + // - Requires a type T to be specified. + // - Throws a std::exception on failure (including wil::ResultException), including registry value not found. + // If you don't want an exception when the value does not exist, use try_get_value(...) + // + // Examples of usage (ensure the code handles a possible std::exception that will be thrown on all errors) + // uint32_t dword_value = wil::reg::get_value(key, L"subkey", L"dword_value_name"); + // uint64_t qword_value = wil::reg::get_value(key, L"subkey", L"qword_value_name); + // std::wstring string_value = wil::reg::get_value(key, L"subkey", L"string_value_name"); + // + // A subkey is not required if the key is opened where this should write the value: + // uint32_t dword_value = wil::reg::get_value(key, L"dword_value_name"); + // uint64_t qword_value = wil::reg::get_value(key, L"qword_value_name); + // std::wstring string_value = wil::reg::get_value(key, L"string_value_name"); + // + // The template type does not need to be specified if using functions written for a targeted type + // uint32_t dword_value = wil::reg::get_value_dword(key, L"dword_value_name"); + // uint64_t qword_value = wil::reg::get_value_qword(key, L"qword_value_name"); + // std::wstring string_value = wil::reg::get_value_string(key, L"string_value_name"); + // + // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: + // std::wstring expanded_string_value = wil::reg::get_value_expanded_string(key, + // L"string_value_name_with_environment_variables"); + // + // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: + // std::vector data = wil::reg::get_value_binary(key, L"binary_value_name", REG_BINARY); + // + // Multi-string values can be read into a vector; e.g.: + // std::vector multi_string_value = wil::reg::get_value_multistring(key, + // L"multi_string_value_name"); for (const auto& sub_string_value : multi_string_value) + // { + // // can read each string parsed from the multi-string + // PCWSTR string_value = sub_string_value.c_str(); + // } + // + // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string and + // get_value_expanded_string functions Where the template type is the type to receive the string value The + // default template type is std::wstring, available if the caller has included the STL header + // + // Reading a bstr can be stored in a wil::shared_bstr or wil::unique_bstr - wil::shared_bstr has a c'tor taking + // a wil::unique_bstr + // wil::unique_bstr unique_value { wil::reg::get_value_string<::wil::unique_bstr>(key, L"string_value_name") + // }; wil::shared_bstr shared_value { wil::reg::get_value_string<::wil::shared_bstr>(key, + // L"string_value_name") }; + // + // Reading a cotaskmem string can be stored in a wil::unique_cotaskmem_string or wil::shared_cotaskmem_string + // wil::unique_cotaskmem_string unique_value { wil::reg::get_value_string(key, + // L"string_value_name") }; wil::shared_cotaskmem_string shared_value { + // wil::reg::get_value_string(key, L"string_value_name") }; + // + // Blocking get_value_string template types that are not already specialized - this gives a much friendlier + // compiler error message + template + T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); + } + + template T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); + } + + template + T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); + } + + template T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); + } + + /** + * @brief Reads a value from a specified key and subkey, deducing registry type from the type parameter T. + * @tparam T The type to read (the registry value type is deduced from T) + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type T + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template T get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + T return_value{}; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, return_value); + return return_value; + } + + /** + * @brief Reads a value under a specified key, deducing registry type from the type parameter T. + * @tparam T The type to read (the registry value type is deduced from T) + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type T + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template T get_value(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value(key, nullptr, value_name); + } + + /** + * @brief Reads a REG_DWORD value, returning a uint32_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The uint32_t value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value(key, subkey, value_name); + } + + /** + * @brief Reads a REG_DWORD value, returning a uint32_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The uint32_t value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value(key, nullptr, value_name); + } + + /** + * @brief Reads a REG_QWORD value, returning a uint64_t + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The uint64_t value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value(key, subkey, value_name); + } + + /** + * @brief Reads a REG_QWORD value, returning a uint64_t + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The uint64_t value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value(key, nullptr, value_name); + } + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); + } + + /** + * @brief Reads a REG_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); + } + + /** + * @brief Reads a REG_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); + } + + /** + * @brief Reads a REG_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); + } + + /** + * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + ::std::wstring value; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } - if (!::wil::reg::is_registry_not_found(hr)) + /** + * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) { - THROW_HR(HRESULT_FROM_WIN32(hr)); + return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); } - return ::std::nullopt; - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value_expanded_string(key, subkey, value_name); + } - /** - * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } - - /** - * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, subkey, value_name); - } - - /** - * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * @return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A std::wstring created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); + } #endif -#endif -#endif - - // - // template - // HRESULT get_value_nothrow(...) - // - // - Reads a value from under a specified key - // - The required type of registry value being read from is determined by the template type T - // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) - // - // Examples of usage (the template type does not need to be explicitly specified) - // uint32_t dword_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"dword_value_name", &dword_value); // reads a REG_DWORD - // uint64_t qword_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"qword_value_name", &qword_value); // reads a REG_QWORD - // wil::unique_bstr string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"string_value_name", string_value); // reads a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // hr = wil::reg::get_value_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD - // hr = wil::reg::get_value_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ - // - // Can also specify the registry type in the function name: - // hr = wil::reg::get_value_dword_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD - // hr = wil::reg::get_value_qword_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ - // - // Example storing directly into a WCHAR array - note will return the required number of bytes if the supplied array is too small - // WCHAR string_value[100]{}; - // uint32_t requiredBytes{}; - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value, &requiredBytes); - // - // Example of usage writing a REG_MULTI_SZ - // wil::unique_cotaskmem_array_ptr string_values{}; - // hr = wil::reg::get_value_multistring_nothrow(key, L"multi_string_value_name", string_values); - // - // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: - // wil::unique_cotaskmem_array_ptr raw_value{}; - // hr = wil::reg::get_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, raw_value); - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string_nothrow and get_value_expanded_string_nothrow functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Example storing a string in a wil::unique_bstr, wil::shared_bstr, wil::unique_cotaskmem_string, or wil::shared_cotaskmem_string - /// - These string types are passed by reference, not by pointer, because the wil types overload the & operator - // - // wil::unique_bstr bstr_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", bstr_value); - // // or can specify explicitly reading a string into a wil::unique_bstr type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", bstr_value); - // - // wil::shared_bstr shared_bstr_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_bstr_value); - // // or can specify explicitly reading a string into a wil::shared_bstr type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_bstr_value); - // - // wil::unique_cotaskmem_string string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); - // // or can specify explicitly reading a string into a wil::unique_cotaskmem_string type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); - // - // wil::shared_cotaskmem_string shared_string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_string_value); - // // or can specify explicitly reading a string into a wil::shared_cotaskmem_string type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_string_value); - // - - /** - * @brief Reads a value under a specified key, the registry type based off the templated type passed as data - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A pointer-to-T receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template >* = nullptr> - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value(subkey, value_name, *return_value); - } - - /** - * @brief Reads a value under a specified key, the registry type based off the templated type passed as data - * @tparam T The type of the data being set (the registry value type is deduced from T). - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A pointer-to-T receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template >* = nullptr> - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @param[out] requiredBytes An optional pointer to a unsigned 32-bit value to receive the required bytes of the string in the - * registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, requiredBytes); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @param[out] requiredBytes An optional pointer to an unsigned 32-bit value to receive the required bytes of the string to be - * read - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - constexpr uint32_t* null_out_param = nullptr; - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, null_out_param); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, subkey, value_name, return_value); - } - - /** - * @brief Reads a REG_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } - - /** - * @brief Reads a REG_DWORD value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ DwordType* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * @brief Reads a REG_DWORD value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ DwordType* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * @brief Reads a REG_QWORD value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A uint64_t receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ QwordType* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * @brief Reads a REG_QWORD value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A uint64_t receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ QwordType* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value(subkey, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::unique_bstr + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_bstr created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::unique_bstr>(key, subkey, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::unique_bstr + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_bstr created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::unique_bstr>(key, nullptr, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_bstr created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + ::wil::unique_bstr value; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); + return value; + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_bstr created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value_expanded_string<::wil::unique_bstr>(key, nullptr, value_name); + } #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value(subkey, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::shared_bstr + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_bstr created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::shared_bstr>(key, subkey, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::shared_bstr + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_bstr created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::shared_bstr>(key, nullptr, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_bstr created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + ::wil::shared_bstr value; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); + return value; + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_bstr + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_bstr created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); + } #endif // #if defined(__WIL_OLEAUTO_H_STL) #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return_value.reset(); - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value(subkey, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_cotaskmem_string created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, subkey, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_cotaskmem_string created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, nullptr, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_cotaskmem_string created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + ::wil::unique_cotaskmem_string value; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); + return value; + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::unique_cotaskmem_string created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return wil::reg::get_value_expanded_string<::wil::unique_cotaskmem_string>(key, nullptr, value_name); + } #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return_value.reset(); - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value(subkey, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_cotaskmem_string created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, subkey, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_cotaskmem_string created from the string value read from the registry + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, nullptr, value_name); + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_cotaskmem_string created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + ::wil::shared_cotaskmem_string value; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); + return value; + } - /** - * @brief Reads a REG_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A wil::shared_cotaskmem_string created from the string value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + template <> + inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return wil::reg::get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); + } #endif // #if defined(__WIL_OBJBASE_H_STL) #endif // defined(__WIL_OBJBASE_H_) -#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads the raw bytes from a registry value under a specified key of the specified type - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_binary_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT - { - // zero the vector if it already had a buffer - for (auto& byte_value : return_value) +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Reads a registry value of the specified type, returning a std::vector + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @return A std::vector containing the bytes of the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + uint32_t type) { - byte_value = 0x00; + ::std::vector return_value{}; + const reg_view_details::reg_view regview{key}; + regview.get_value(subkey, value_name, return_value, type); + return return_value; } - const reg_view_details::reg_view_nothrow regview{key}; - RETURN_IF_FAILED(regview.get_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, return_value, type)); - return S_OK; - } - /** - * @brief Reads the raw bytes from a registry value under a specified key of the specified type - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param type The registry type for the specified registry value to read from - see RegGetValueW - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_binary_nothrow( - HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_binary_nothrow(key, nullptr, value_name, type, return_value); - } + /** + * @brief Reads a registry value of the specified type, returning a std::vector + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @return A std::vector containing the bytes of the specified registry value + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + */ + inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) + { + return ::wil::reg::get_value_binary(key, nullptr, value_name, type); + } +#endif + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_MULTI_SZ value, returning a std::vector + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. + * See remarks. + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + * + * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null + * character e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" returns a vector of size 5: L"string1", + * empty-string, L"string2", empty-string, L"string3" + */ + template <> + inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + ::std::vector<::std::wstring> return_value; + ::std::vector rawData{::wil::reg::get_value_binary(key, subkey, value_name, REG_MULTI_SZ)}; + if (!rawData.empty()) + { + auto *const begin = reinterpret_cast(rawData.data()); + auto *const end = begin + rawData.size() / sizeof(wchar_t); + return_value = ::wil::reg::reg_view_details::get_wstring_vector_from_multistring(begin, end); + } + + return return_value; + } + + /** + * @brief Reads a REG_MULTI_SZ value, returning a std::vector + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. + * See remarks. + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + * + * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null + * character e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" returns a vector of size 5: L"string1", + * empty-string, L"string2", empty-string, L"string3" + */ + template <> + inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); + } + + /** + * @brief Reads a REG_MULTI_SZ value, returning a std::vector + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. + * See remarks. + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + * + * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null + * character e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" returns a vector of size 5: L"string1", + * empty-string, L"string2", empty-string, L"string3" + */ + inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, subkey, value_name); + } + + /** + * @brief Reads a REG_MULTI_SZ value, returning a std::vector + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. + * See remarks. + * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value + * not found + * + * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null + * character e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" returns a vector of size 5: L"string1", + * empty-string, L"string2", empty-string, L"string3" + */ + inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); + } +#endif + +#if (WIL_USE_STL && (__cpp_lib_optional >= 201606L)) || defined(WIL_DOXYGEN) + // + // template + // void try_get_value(...) + // + // - Reads a value under a specified key and subkey, deducing registry type from the type parameter T. + // - throws a std::exception on failure (including wil::ResultException), except if the registry value was not + // found + // returns a std::nullopt if the registry value is not found + // + // Examples using the returned std::optional + // - Caller should ensure the code handles a possible std::exception that will be thrown on all errors except + // value not found + // + // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); + // if (opt_dword_value.has_value()) + // { + // // opt_dword_value.value() returns the uint32_t read from the registry + // } + // else + // { + // // the registry value did not exist + // } + // // if the caller wants to apply a default value of 0, they can call value_or() + // uint32_t opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name").value_or(0); + // + // Examples using the returned std::optional + // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); + // if (opt_string_value.has_value()) + // { + // // opt_string_value.value() returns the std::wstring read from the registry + // // the below avoids copying the std::wstring as value() here returns a std::wstring& + // PCWSTR string_value = opt_string_value.value().c_str(); + // } + // else + // { + // // the registry value did not exist + // } + // + // // if the caller wants to apply a default value of L"default", they can call value_or() + // // note that std::optional only attempts to construct a std::wstring for L"default" if the std::optional + // is empty (std::nullopt) + // // thus only allocating a new std::wstring for the default value when it's needed + // std::optional opt_string_value = wil::reg::try_get_value_string(key, + // L"string_value_name").value_or(L"default"); + // + // Examples of usage: + // std::optional opt_dword_value = wil::reg::try_get_value(key, L"subkey", + // L"dword_value_name"); std::optional opt_qword_value = wil::reg::try_get_value(key, + // L"subkey", L"qword_value_name); std::optional opt_string_value = + // wil::reg::try_get_value(key, L"subkey", L"string_value_name"); + // + // A subkey is not required if the key is opened where this should write the value; e.g. + // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); + // std::optional opt_qword_value = wil::reg::try_get_value(key, L"qword_value_name); + // std::optional opt_string_value = wil::reg::try_get_value(key, + // L"string_value_name"); + // + // The template type does not need to be specified if using functions written for a targeted type; e.g. + // std::optional opt_dword_value = wil::reg::try_get_value_dword(key, L"dword_value_name"); + // std::optional opt_qword_value = wil::reg::try_get_value_qword(key, L"qword_value_name"); + // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); + // + // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: + // std::optional opt_expanded_string_value = wil::reg::try_get_value_expanded_string(key, + // L"string_value_name_with_environment_variables"); + // + // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: + // std::optional> opt_data = wil::reg::try_get_value_binary(key, L"binary_value_name", + // REG_BINARY); + // + // Multi-string values can be read into a std::vector; e.g.: + // std::optional<::std::vector<::std::wstring>> try_get_value_multistring(key, L"multi_string_value_name"); + // See the definition of try_get_value_multistring before for usage guidance + // + // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated try_get_value_string and + // try_get_value_expanded_string functions Where the template type is the type to receive the string value The + // default template type is std::wstring, available if the caller has included the STL header + // + // Reading a bstr is returned in a std::optional - because wil::unique_bstr cannot be copied + // and thus is difficult to work with a std::optional + // std::optional shared_value { wil::reg::try_get_value_string<::wil::shared_bstr>(key, + // L"string_value_name") }; + // + // Reading a cotaskmem string is returned in a std::optional - because + // wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional + // std::optional opt_shared_value { + // wil::reg::try_get_value_string(key, L"string_value_name") }; + // + // Blocking try_get_value_string template types that are not already specialized - this gives a much friendlier + // compiler error message + template + ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, + _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); + } + + template ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); + } + + template + ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, + _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); + } + + template + ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); + } + + /** + * @brief Attempts to read a value under a specified key and subkey, returning in a std::optional, deducing + * registry type from the type parameter T. + * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced + * from T) + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value (of type T) read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template + ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { +#if defined(__WIL_OLEAUTO_H_) + // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to + // work with a std::optional + static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); +#endif // #if defined(__WIL_OLEAUTO_H_) +#if defined(__WIL_OBJBASE_H_) + // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is + // difficult to work with a std::optional + static_assert(!wistd::is_same_v, + "try_get with wil::unique_cotaskmem_string is disabled"); #endif // #if defined(__WIL_OBJBASE_H_) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_expanded_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, requiredBytes); - } + const reg_view_details::reg_view regview{key}; + return regview.try_get_value(subkey, value_name); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_expanded_string_nothrow( - HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); - } + /** + * @brief Attempts to read a value under a specified key, returning the value in a std::optional, deducing + * registry type from the type parameter T. + * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced + * from T) + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value (of type T) read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR value_name) + { +#if defined(__WIL_OLEAUTO_H_) + // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to + // work with a std::optional + static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); +#endif // #if defined(__WIL_OLEAUTO_H_) +#if defined(__WIL_OBJBASE_H_) + // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is + // difficult to work with a std::optional + static_assert(!wistd::is_same_v, + "try_get with wil::unique_cotaskmem_string is disabled"); +#endif // #if defined(__WIL_OBJBASE_H_) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - constexpr uint32_t* null_out_param = nullptr; - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, null_out_param); - } + return ::wil::reg::try_get_value(key, nullptr, value_name); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @tparam Length The length of the WCHAR array passed as an OUT parameter - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value(key, subkey, value_name); + } -#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value<::wil::unique_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); - } + /** + * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value(key, nullptr, value_name); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value(key, subkey, value_name); + } + + /** + * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value(key, nullptr, value_name); + } + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes + * in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @return The raw bytes read from the registry value stored in a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name, uint32_t type) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::std::vector>(subkey, value_name, type); + } + + /** + * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes + * in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @return The raw bytes read from the registry value stored in a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, + uint32_t type) + { + return ::wil::reg::try_get_value_binary(key, nullptr, value_name, type); + } +#endif + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::std::wstring>(subkey, value_name); + } + + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_string(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_string(key, subkey, value_name); + } + + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value, in a std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_string(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::std::wstring>(subkey, value_name, REG_EXPAND_SZ); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, + _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_expanded_string(key, subkey, value_name); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); + } +#endif #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value<::wil::shared_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); - } + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, + _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::wil::shared_bstr>(subkey, value_name); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_string<::wil::shared_bstr>(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::wil::shared_bstr>(subkey, value_name, REG_EXPAND_SZ); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type std::optional, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); + } +#endif // #if defined(__WIL_OLEAUTO_H_STL) + +#if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type + * std::optional. Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name); + } + + /** + * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type + * std::optional Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type + * std::optional<:wil::shared_cotaskmem_string>, with environment variables expanded, as though passed through + * ExpandEnvironmentStringsW. Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string< + ::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + const reg_view_details::reg_view regview{key}; + return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name, REG_EXPAND_SZ); + } + + /** + * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value of the template type + * std::optional, with environment variables expanded, as though passed through + * ExpandEnvironmentStringsW. Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string< + ::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); + } +#endif // defined(__WIL_OBJBASE_H_STL) + +#if WIL_USE_STL || defined(WIL_DOXYGEN) + /** + * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value marshaled to a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) + { + ::std::vector<::std::wstring> value; + const auto hr = + ::wil::ResultFromException([&] { value = ::wil::reg::get_value_multistring(key, subkey, value_name); }); + if (SUCCEEDED(hr)) + { + return value; + } + + if (!::wil::reg::is_registry_not_found(hr)) + { + THROW_HR(HRESULT_FROM_WIN32(hr)); + } + + return ::std::nullopt; + } + + /** + * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value marshaled to a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + template <> + inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>( + HKEY key, _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); + } + + /** + * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value marshaled to a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, + _In_opt_ PCWSTR subkey, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, subkey, value_name); + } + + /** + * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be updated. + * Can be nullptr to read from the unnamed default registry value. + * @return The value read from the registry value marshaled to a std::optional>. + * Returns std::nullopt if the value does not exist. + * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found + */ + inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, + _In_opt_ PCWSTR value_name) + { + return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); + } +#endif +#endif +#endif + + // + // template + // HRESULT get_value_nothrow(...) + // + // - Reads a value from under a specified key + // - The required type of registry value being read from is determined by the template type T + // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) + // + // Examples of usage (the template type does not need to be explicitly specified) + // uint32_t dword_value{}; + // hr = wil::reg::get_value_nothrow(key, L"subkey", L"dword_value_name", &dword_value); // reads a REG_DWORD + // uint64_t qword_value{}; + // hr = wil::reg::get_value_nothrow(key, L"subkey", L"qword_value_name", &qword_value); // reads a REG_QWORD + // wil::unique_bstr string_value{}; + // hr = wil::reg::get_value_nothrow(key, L"subkey", L"string_value_name", string_value); // reads a REG_SZ + // + // A subkey is not required if the key is opened where this should write the value: + // hr = wil::reg::get_value_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD + // hr = wil::reg::get_value_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD + // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ + // + // Can also specify the registry type in the function name: + // hr = wil::reg::get_value_dword_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD + // hr = wil::reg::get_value_qword_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ + // + // Example storing directly into a WCHAR array - note will return the required number of bytes if the supplied + // array is too small + // WCHAR string_value[100]{}; + // uint32_t requiredBytes{}; + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value, &requiredBytes); + // + // Example of usage writing a REG_MULTI_SZ + // wil::unique_cotaskmem_array_ptr string_values{}; + // hr = wil::reg::get_value_multistring_nothrow(key, L"multi_string_value_name", string_values); + // + // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: + // wil::unique_cotaskmem_array_ptr raw_value{}; + // hr = wil::reg::get_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, raw_value); + // + // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string_nothrow and + // get_value_expanded_string_nothrow functions Where the template type is the type to receive the string value + // The default template type is std::wstring, available if the caller has included the STL header + // + // Example storing a string in a wil::unique_bstr, wil::shared_bstr, wil::unique_cotaskmem_string, or + // wil::shared_cotaskmem_string + /// - These string types are passed by reference, not by pointer, because the wil types overload the & operator + // + // wil::unique_bstr bstr_value{}; + // hr = wil::reg::get_value_nothrow(key, L"string_value_name", bstr_value); + // // or can specify explicitly reading a string into a wil::unique_bstr type + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", bstr_value); + // + // wil::shared_bstr shared_bstr_value{}; + // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_bstr_value); + // // or can specify explicitly reading a string into a wil::shared_bstr type + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_bstr_value); + // + // wil::unique_cotaskmem_string string_value{}; + // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); + // // or can specify explicitly reading a string into a wil::unique_cotaskmem_string type + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); + // + // wil::shared_cotaskmem_string shared_string_value{}; + // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_string_value); + // // or can specify explicitly reading a string into a wil::shared_cotaskmem_string type + // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_string_value); + // + + /** + * @brief Reads a value under a specified key, the registry type based off the templated type passed as data + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A pointer-to-T receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template > * = nullptr> + HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + _Out_ T *return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value(subkey, value_name, *return_value); + } + + /** + * @brief Reads a value under a specified key, the registry type based off the templated type passed as data + * @tparam T The type of the data being set (the registry value type is deduced from T). + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A pointer-to-T receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template > * = nullptr> + HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ T *return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @param[out] requiredBytes An optional pointer to a unsigned 32-bit value to receive the required bytes of the + * string in the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length], _Out_opt_ DwordType *requiredBytes) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, requiredBytes); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @param[out] requiredBytes An optional pointer to an unsigned 32-bit value to receive the required bytes of + * the string to be read + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], + _Out_opt_ DwordType *requiredBytes) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + constexpr uint32_t *null_out_param = nullptr; + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, null_out_param); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_DWORD value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + _Out_ DwordType *return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_DWORD value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ DwordType *return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_QWORD value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A uint64_t receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + _Out_ QwordType *return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_QWORD value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A uint64_t receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ QwordType *return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + +#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value(subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); + } + +#if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value(subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); + } #endif // #if defined(__WIL_OLEAUTO_H_STL) #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value<::wil::unique_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); - } + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + return_value.reset(); + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value(subkey, value_name, return_value); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow( - HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{key}; - return regview.get_value<::wil::shared_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); - } + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + return_value.reset(); + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value(subkey, value_name, return_value); + } - /** - * @brief Reads a REG_EXPAND_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } #endif // #if defined(__WIL_OBJBASE_H_STL) #endif // defined(__WIL_OBJBASE_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) - /** - * @brief Reads a REG_MULTI_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from - * the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow( - HKEY key, - _In_opt_ PCWSTR subkey, - _In_opt_ PCWSTR value_name, - ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - ::wil::unique_cotaskmem_array_ptr rawData; - RETURN_IF_FAILED(::wil::reg::get_value_binary_nothrow(key, subkey, value_name, REG_MULTI_SZ, rawData)); - if (!rawData.empty()) + /** + * @brief Reads the raw bytes from a registry value under a specified key of the specified type + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + uint32_t type, + ::wil::unique_cotaskmem_array_ptr &return_value) WI_NOEXCEPT { - auto* const begin = reinterpret_cast(rawData.data()); - auto* const end = begin + rawData.size() / sizeof(wchar_t); - ::wil::reg::reg_view_details::get_cotaskmemstring_array_from_multistring_nothrow(begin, end, return_value); + // zero the vector if it already had a buffer + for (auto &byte_value : return_value) + { + byte_value = 0x00; + } + const reg_view_details::reg_view_nothrow regview{key}; + RETURN_IF_FAILED( + regview.get_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, return_value, type)); + return S_OK; } - return S_OK; - } - /** - * @brief Reads a REG_MULTI_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from - * the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow( - HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * @brief Reads a REG_MULTI_SZ value under a specified key - * @param key An open or well-known registry key - * @param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from - * the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_multistring_nothrow( - HKEY key, - _In_opt_ PCWSTR subkey, - _In_opt_ PCWSTR value_name, - ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * @brief Reads a REG_MULTI_SZ value under a specified key - * @param key An open or well-known registry key - * @param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from - * the registry - * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_multistring_nothrow( - HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } + /** + * @brief Reads the raw bytes from a registry value under a specified key of the specified type + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param type The registry type for the specified registry value to read from - see RegGetValueW + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, + ::wil::unique_cotaskmem_array_ptr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_binary_nothrow(key, nullptr, value_name, type, return_value); + } #endif // #if defined(__WIL_OBJBASE_H_) -} // namespace reg -// unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast -// These classes make it easy to execute a provided function when a -// registry key changes (optionally recursively). Specify the key -// either as a root key + path, or an open registry handle as wil::unique_hkey -// or a raw HKEY value (that will be duplicated). -// -// Example use with exceptions base error handling: -// auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[] -// { -// if (changeKind == RegistryChangeKind::Delete) -// { -// watcher.reset(); -// } -// // invalidate cached registry data here -// }); -// -// Example use with error code base error handling: -// auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[] -// { -// // invalidate cached registry data here -// }); -// RETURN_IF_NULL_ALLOC(watcher); + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be + * read + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length], + _Out_opt_ DwordType *requiredBytes) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, requiredBytes); + } -enum class RegistryChangeKind -{ - Modify = 0, - Delete = 1, -}; + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be + * read + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template || + wistd::is_same_v> * = nullptr> + HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], + _Out_opt_ DwordType *requiredBytes) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value, + requiredBytes); + } -/// @cond -namespace details -{ - struct registry_watcher_state + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + constexpr uint32_t *null_out_param = nullptr; + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, null_out_param); + } + + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @tparam Length The length of the WCHAR array passed as an OUT parameter + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A WCHAR array receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * Will write to the WCHAR array the string value read from the registry, guaranteeing + * null-termination + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + template + HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length]) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); + } + +#if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value<::wil::unique_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); + } + + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); + } + +#if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value<::wil::shared_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); + } + + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_bstr &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); + } +#endif // #if defined(__WIL_OLEAUTO_H_STL) +#endif // #if defined(__WIL_OLEAUTO_H_) + +#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value<::wil::unique_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); + } + + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); + } + +#if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + const reg_view_details::reg_view_nothrow regview{key}; + return regview.get_value<::wil::shared_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); + } + + /** + * @brief Reads a REG_EXPAND_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, + * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, + ::wil::shared_cotaskmem_string &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); + } +#endif // #if defined(__WIL_OBJBASE_H_STL) +#endif // defined(__WIL_OBJBASE_H_) + +#if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) + /** + * @brief Reads a REG_MULTI_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the + * value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> &return_value) WI_NOEXCEPT + { + ::wil::unique_cotaskmem_array_ptr rawData; + RETURN_IF_FAILED(::wil::reg::get_value_binary_nothrow(key, subkey, value_name, REG_MULTI_SZ, rawData)); + if (!rawData.empty()) + { + auto *const begin = reinterpret_cast(rawData.data()); + auto *const end = begin + rawData.size() / sizeof(wchar_t); + ::wil::reg::reg_view_details::get_cotaskmemstring_array_from_multistring_nothrow(begin, end, + return_value); + } + return S_OK; + } + + /** + * @brief Reads a REG_MULTI_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the + * value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_nothrow( + HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } + + /** + * @brief Reads a REG_MULTI_SZ value under a specified key + * @param key An open or well-known registry key + * @param subkey The name of the subkey to append to `key`. + * If `nullptr`, then `key` is used without modification. + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the + * value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_multistring_nothrow( + HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); + } + + /** + * @brief Reads a REG_MULTI_SZ value under a specified key + * @param key An open or well-known registry key + * @param value_name The name of the registry value whose data is to be read. + * Can be nullptr to read from the unnamed default registry value. + * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the + * value read from the registry + * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) + */ + inline HRESULT get_value_multistring_nothrow( + HKEY key, _In_opt_ PCWSTR value_name, + ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> &return_value) WI_NOEXCEPT + { + return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); + } +#endif // #if defined(__WIL_OBJBASE_H_) + } // namespace reg + + // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast + // These classes make it easy to execute a provided function when a + // registry key changes (optionally recursively). Specify the key + // either as a root key + path, or an open registry handle as wil::unique_hkey + // or a raw HKEY value (that will be duplicated). + // + // Example use with exceptions base error handling: + // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind + // changeKind[] + // { + // if (changeKind == RegistryChangeKind::Delete) + // { + // watcher.reset(); + // } + // // invalidate cached registry data here + // }); + // + // Example use with error code base error handling: + // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, + // wil::RegistryChangeKind[] + // { + // // invalidate cached registry data here + // }); + // RETURN_IF_NULL_ALLOC(watcher); + + enum class RegistryChangeKind { - registry_watcher_state(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) : - m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) - { - } - wistd::function m_callback; - unique_hkey m_keyToWatch; - unique_event_nothrow m_eventHandle; - - // While not strictly needed since this is ref counted the thread pool wait - // should be last to ensure that the other members are valid - // when it is destructed as it will reference them. - unique_threadpool_wait m_threadPoolWait; - bool m_isRecursive; - - volatile long m_refCount = 1; - srwlock m_lock; - - // Returns true if the ref-count can be increased from a non zero value, - // false it was zero implying that the object is in or on the way to the destructor. - // In this case ReleaseFromCallback() should not be called. - bool TryAddRef() - { - return ::InterlockedIncrement(&m_refCount) > 1; - } - - void Release() - { - auto lock = m_lock.lock_exclusive(); - if (0 == ::InterlockedDecrement(&m_refCount)) - { - lock.reset(); // leave the lock before deleting it. - delete this; - } - } - - void ReleaseFromCallback(bool rearm) - { - auto lock = m_lock.lock_exclusive(); - if (0 == ::InterlockedDecrement(&m_refCount)) - { - // Destroy the thread pool wait now to avoid the wait that would occur in the - // destructor. That wait would cause a deadlock since we are doing this from the callback. - ::CloseThreadpoolWait(m_threadPoolWait.release()); - lock.reset(); // leave the lock before deleting it. - delete this; - // Sleep(1); // Enable for testing to find use after free bugs. - } - else if (rearm) - { - ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); - } - } + Modify = 0, + Delete = 1, }; - inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state* watcherStorage) + /// @cond + namespace details { - watcherStorage->Release(); - } - - typedef resource_policy - registry_watcher_state_resource_policy; -} // namespace details -/// @endcond - -template -class registry_watcher_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) - { - } - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(rootKey, subKey, isRecursive, wistd::move(callback)); - } - - registry_watcher_t(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - } - - // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. - result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - // Most use will want to create the key, consider adding an option for open as a future design change. - unique_hkey keyToWatch; - HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); - if (FAILED(hr)) + struct registry_watcher_state { - return err_policy::HResult(hr); + registry_watcher_state(unique_hkey &&keyToWatch, bool isRecursive, + wistd::function &&callback) + : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) + { + } + wistd::function m_callback; + unique_hkey m_keyToWatch; + unique_event_nothrow m_eventHandle; + + // While not strictly needed since this is ref counted the thread pool wait + // should be last to ensure that the other members are valid + // when it is destructed as it will reference them. + unique_threadpool_wait m_threadPoolWait; + bool m_isRecursive; + + volatile long m_refCount = 1; + srwlock m_lock; + + // Returns true if the ref-count can be increased from a non zero value, + // false it was zero implying that the object is in or on the way to the destructor. + // In this case ReleaseFromCallback() should not be called. + bool TryAddRef() + { + return ::InterlockedIncrement(&m_refCount) > 1; + } + + void Release() + { + auto lock = m_lock.lock_exclusive(); + if (0 == ::InterlockedDecrement(&m_refCount)) + { + lock.reset(); // leave the lock before deleting it. + delete this; + } + } + + void ReleaseFromCallback(bool rearm) + { + auto lock = m_lock.lock_exclusive(); + if (0 == ::InterlockedDecrement(&m_refCount)) + { + // Destroy the thread pool wait now to avoid the wait that would occur in the + // destructor. That wait would cause a deadlock since we are doing this from the callback. + ::CloseThreadpoolWait(m_threadPoolWait.release()); + lock.reset(); // leave the lock before deleting it. + delete this; + // Sleep(1); // Enable for testing to find use after free bugs. + } + else if (rearm) + { + ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); + } + } + }; + + inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state *watcherStorage) + { + watcherStorage->Release(); } - return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - } - result create(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - } + typedef resource_policy + registry_watcher_state_resource_policy; + } // namespace details + /// @endcond -private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback(PTP_CALLBACK_INSTANCE, void* context, TP_WAIT*, TP_WAIT_RESULT) + template + class registry_watcher_t : public storage_t { + public: + // forward all base class constructors... + template + explicit registry_watcher_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) + { + } + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, + wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions; use the create method"); + create(rootKey, subKey, isRecursive, wistd::move(callback)); + } + + registry_watcher_t(unique_hkey &&keyToWatch, bool isRecursive, + wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions; use the create method"); + create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } + + // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. + result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, + wistd::function &&callback) + { + // Most use will want to create the key, consider adding an option for open as a future design change. + unique_hkey keyToWatch; + HRESULT hr = HRESULT_FROM_WIN32( + RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); + if (FAILED(hr)) + { + return err_policy::HResult(hr); + } + return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + } + + result create(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + } + + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *, TP_WAIT_RESULT) + { #ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST #define __WIL_REGISTRY_CHANGE_CALLBACK_TEST #endif - __WIL_REGISTRY_CHANGE_CALLBACK_TEST - const auto watcherState = static_cast(context); - if (watcherState->TryAddRef()) - { - // using auto reset event so don't need to manually reset. - - // failure here is a programming error. - const LSTATUS error = RegNotifyChangeKeyValue( - watcherState->m_keyToWatch.get(), - watcherState->m_isRecursive, - REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, - watcherState->m_eventHandle.get(), - TRUE); - - // Call the client before re-arming to ensure that multiple callbacks don't - // run concurrently. - switch (error) + __WIL_REGISTRY_CHANGE_CALLBACK_TEST + const auto watcherState = static_cast(context); + if (watcherState->TryAddRef()) { - case ERROR_SUCCESS: - case ERROR_ACCESS_DENIED: - // Normal modification: send RegistryChangeKind::Modify and re-arm. - watcherState->m_callback(RegistryChangeKind::Modify); - watcherState->ReleaseFromCallback(true); - break; + // using auto reset event so don't need to manually reset. - case ERROR_KEY_DELETED: - // Key deleted, send RegistryChangeKind::Delete, do not re-arm. - watcherState->m_callback(RegistryChangeKind::Delete); - watcherState->ReleaseFromCallback(false); - break; + // failure here is a programming error. + const LSTATUS error = RegNotifyChangeKeyValue( + watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, + REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, + watcherState->m_eventHandle.get(), TRUE); - case ERROR_HANDLE_REVOKED: - // Handle revoked. This can occur if the user session ends before - // the watcher shuts-down. Disarm silently since there is generally no way to respond. - watcherState->ReleaseFromCallback(false); - break; + // Call the client before re-arming to ensure that multiple callbacks don't + // run concurrently. + switch (error) + { + case ERROR_SUCCESS: + case ERROR_ACCESS_DENIED: + // Normal modification: send RegistryChangeKind::Modify and re-arm. + watcherState->m_callback(RegistryChangeKind::Modify); + watcherState->ReleaseFromCallback(true); + break; - default: - FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); + case ERROR_KEY_DELETED: + // Key deleted, send RegistryChangeKind::Delete, do not re-arm. + watcherState->m_callback(RegistryChangeKind::Delete); + watcherState->ReleaseFromCallback(false); + break; + + case ERROR_HANDLE_REVOKED: + // Handle revoked. This can occur if the user session ends before + // the watcher shuts-down. Disarm silently since there is generally no way to respond. + watcherState->ReleaseFromCallback(false); + break; + + default: + FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); + } } } - } - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(unique_hkey &&keyToWatch, bool isRecursive, + wistd::function &&callback) + { + wistd::unique_ptr watcherState( + new (std::nothrow) + details::registry_watcher_state(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + RETURN_IF_FAILED(watcherState->m_eventHandle.create()); + RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, + REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | + REG_NOTIFY_THREAD_AGNOSTIC, + watcherState->m_eventHandle.get(), TRUE)); + + watcherState->m_threadPoolWait.reset( + CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + storage_t::reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); + return S_OK; + } + }; + + typedef unique_any_t, + err_returncode_policy>> + unique_registry_watcher_nothrow; + typedef unique_any_t, + err_failfast_policy>> + unique_registry_watcher_failfast; + + inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( + HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, + wistd::function &&callback) WI_NOEXCEPT { - wistd::unique_ptr watcherState( - new (std::nothrow) details::registry_watcher_state(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - RETURN_IF_FAILED(watcherState->m_eventHandle.create()); - RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue( - watcherState->m_keyToWatch.get(), - watcherState->m_isRecursive, - REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, - watcherState->m_eventHandle.get(), - TRUE)); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - storage_t::reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); - return S_OK; + unique_registry_watcher_nothrow watcher; + watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) } -}; -typedef unique_any_t, err_returncode_policy>> unique_registry_watcher_nothrow; -typedef unique_any_t, err_failfast_policy>> unique_registry_watcher_failfast; + inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( + unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) WI_NOEXCEPT + { + unique_registry_watcher_nothrow watcher; + watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } -inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( - HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT -{ - unique_registry_watcher_nothrow watcher; - watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} + inline unique_registry_watcher_failfast make_registry_watcher_failfast( + HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); + } -inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( - unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT -{ - unique_registry_watcher_nothrow watcher; - watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} - -inline unique_registry_watcher_failfast make_registry_watcher_failfast( - HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) -{ - return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); -} - -inline unique_registry_watcher_failfast make_registry_watcher_failfast( - unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) -{ - return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); -} + inline unique_registry_watcher_failfast make_registry_watcher_failfast( + unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } #ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_registry_watcher; + typedef unique_any_t, + err_exception_policy>> + unique_registry_watcher; -inline unique_registry_watcher make_registry_watcher( - HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) -{ - return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); -} + inline unique_registry_watcher make_registry_watcher(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, + wistd::function &&callback) + { + return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); + } -inline unique_registry_watcher make_registry_watcher(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) -{ - return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); -} + inline unique_registry_watcher make_registry_watcher(unique_hkey &&keyToWatch, bool isRecursive, + wistd::function &&callback) + { + return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } #endif // WIL_ENABLE_EXCEPTIONS } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry_helpers.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry_helpers.h index 4e57f10..d4a20a6 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry_helpers.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/registry_helpers.h @@ -26,9 +26,9 @@ #endif #endif -#include -#include #include "resource.h" +#include +#include #ifdef _KERNEL_MODE #error This header is not supported in kernel-mode. @@ -36,1924 +36,1898 @@ namespace wil { -namespace reg -{ - /** - * @brief Helper function to translate registry return values if the value was not found - * @param hr HRESULT to test from registry APIs - * @return boolean if the HRESULT indicates the registry value was not found - */ - constexpr bool is_registry_not_found(HRESULT hr) WI_NOEXCEPT + namespace reg { - return (hr == __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)); - } - - /** - * @brief Helper function to translate registry return values if the buffer was too small - * @param hr HRESULT to test from registry APIs - * @return boolean if the HRESULT indicates the buffer was too small for the value being read - */ - constexpr bool is_registry_buffer_too_small(HRESULT hr) WI_NOEXCEPT - { - return hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA); - } - - // Access rights for opening registry keys. See https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights. - enum class key_access - { - // Open key for reading. - read, - - // Open key for reading and writing. Equivalent to KEY_ALL_ACCESS. - readwrite, - }; - - /// @cond - namespace reg_view_details - { - constexpr DWORD get_value_flags_from_value_type(DWORD type) WI_NOEXCEPT + /** + * @brief Helper function to translate registry return values if the value was not found + * @param hr HRESULT to test from registry APIs + * @return boolean if the HRESULT indicates the registry value was not found + */ + constexpr bool is_registry_not_found(HRESULT hr) WI_NOEXCEPT { - switch (type) - { - case REG_DWORD: - return RRF_RT_REG_DWORD; - case REG_QWORD: - return RRF_RT_REG_QWORD; - case REG_SZ: - return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND; - case REG_EXPAND_SZ: - return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ; - case REG_MULTI_SZ: - return RRF_RT_REG_MULTI_SZ; - case REG_BINARY: - return RRF_RT_REG_BINARY; - // the caller can directly specify their own flags if they need to - default: - return type; - } - } - - constexpr DWORD get_access_flags(key_access access) WI_NOEXCEPT - { - switch (access) - { - case key_access::read: - return KEY_READ; - case key_access::readwrite: - return KEY_ALL_ACCESS; - } - FAIL_FAST(); - RESULT_NORETURN_RESULT(0); + return (hr == __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || + (hr == __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)); } /** - * @brief A utility function that walks a contiguous wchar_t container looking for strings within a multi-string - * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual - * strings - * @tparam Fn A callback function to be called each time a string is found - given the [begin, end] iterators referencing - * the found string - * @param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * @param func A callback function to be called each time a string is found - given the [begin, end] iterators referencing - * the found string + * @brief Helper function to translate registry return values if the buffer was too small + * @param hr HRESULT to test from registry APIs + * @return boolean if the HRESULT indicates the buffer was too small for the value being read */ - template - void walk_multistring(const InputIt& first, const InputIt& last, Fn func) + constexpr bool is_registry_buffer_too_small(HRESULT hr) WI_NOEXCEPT { - auto current = first; - const auto end_iterator = last; - const auto last_null = (end_iterator - 1); - while (current != end_iterator) - { - // hand rolling ::std::find(current, end_iterator, L'\0'); - // as this may be called when isn't available - auto next = current; - while (next != end_iterator && *next != L'\0') - { - ++next; - } + return hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA); + } - if (next != end_iterator) + // Access rights for opening registry keys. See + // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights. + enum class key_access + { + // Open key for reading. + read, + + // Open key for reading and writing. Equivalent to KEY_ALL_ACCESS. + readwrite, + }; + + /// @cond + namespace reg_view_details + { + constexpr DWORD get_value_flags_from_value_type(DWORD type) WI_NOEXCEPT + { + switch (type) { - // don't add an empty string for the final 2nd-null-terminator - if (next != last_null) - { - // call the function provided with the [begin, end] pair referencing a string found - func(current, next); - } - current = next + 1; - } - else - { - current = next; + case REG_DWORD: + return RRF_RT_REG_DWORD; + case REG_QWORD: + return RRF_RT_REG_QWORD; + case REG_SZ: + return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND; + case REG_EXPAND_SZ: + return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ; + case REG_MULTI_SZ: + return RRF_RT_REG_MULTI_SZ; + case REG_BINARY: + return RRF_RT_REG_BINARY; + // the caller can directly specify their own flags if they need to + default: + return type; + } + } + + constexpr DWORD get_access_flags(key_access access) WI_NOEXCEPT + { + switch (access) + { + case key_access::read: + return KEY_READ; + case key_access::readwrite: + return KEY_ALL_ACCESS; + } + FAIL_FAST(); + RESULT_NORETURN_RESULT(0); + } + + /** + * @brief A utility function that walks a contiguous wchar_t container looking for strings within a + * multi-string + * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate + * into individual strings + * @tparam Fn A callback function to be called each time a string is found - given the [begin, end] + * iterators referencing the found string + * @param first An iterator referencing to the beginning of the target container (like a std::begin + * iterator) + * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) + * @param func A callback function to be called each time a string is found - given the [begin, end] + * iterators referencing the found string + */ + template void walk_multistring(const InputIt &first, const InputIt &last, Fn func) + { + auto current = first; + const auto end_iterator = last; + const auto last_null = (end_iterator - 1); + while (current != end_iterator) + { + // hand rolling ::std::find(current, end_iterator, L'\0'); + // as this may be called when isn't available + auto next = current; + while (next != end_iterator && *next != L'\0') + { + ++next; + } + + if (next != end_iterator) + { + // don't add an empty string for the final 2nd-null-terminator + if (next != last_null) + { + // call the function provided with the [begin, end] pair referencing a string found + func(current, next); + } + current = next + 1; + } + else + { + current = next; + } } } - } #if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) - /** - * @brief A translation function taking iterators referencing std::wstring objects and returns a corresponding - * std::vector to be written to a MULTI_SZ registry value. The translation follows the rules for how - * MULTI_SZ registry values should be formatted, notably how null characters should be embedded within the returned - * vector - * @tparam InputIt An iterator type that references a container that holds std::wstring objects to translate into a - * wchar_t buffer - * @param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * @return A std::vector with the raw wchar_t buffer of bytes prepared to write to a MULTI_SZ registry value - */ - template - ::std::vector get_multistring_from_wstrings(const InputIt& first, const InputIt& last) - { - ::std::vector multistring; - - if (first == last) + /** + * @brief A translation function taking iterators referencing std::wstring objects and returns a + * corresponding std::vector to be written to a MULTI_SZ registry value. The translation follows + * the rules for how MULTI_SZ registry values should be formatted, notably how null characters should be + * embedded within the returned vector + * @tparam InputIt An iterator type that references a container that holds std::wstring objects to translate + * into a wchar_t buffer + * @param first An iterator referencing to the beginning of the target container (like a std::begin + * iterator) + * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) + * @return A std::vector with the raw wchar_t buffer of bytes prepared to write to a MULTI_SZ + * registry value + */ + template + ::std::vector get_multistring_from_wstrings(const InputIt &first, const InputIt &last) { - multistring.push_back(L'\0'); + ::std::vector multistring; + + if (first == last) + { + multistring.push_back(L'\0'); + multistring.push_back(L'\0'); + return multistring; + } + + for (const auto &wstr : ::wil::make_range(first, last)) + { + multistring.insert(multistring.end(), ::std::begin(wstr), ::std::end(wstr)); + multistring.push_back(L'\0'); + } + + // double-null-terminate the last string multistring.push_back(L'\0'); return multistring; } - for (const auto& wstr : ::wil::make_range(first, last)) + /** + * @brief A translation function taking iterators referencing wchar_t characters and returns extracted + * individual std::wstring objects. The translation follows the rules for how MULTI_SZ registry value can be + * formatted, notably with embedded null characters. Note that this conversion avoids returning empty + * std::wstring objects even though the input may contain contiguous null wchar_t values + * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate + * into individual strings + * @param first An iterator referencing to the beginning of the target container (like a std::begin + * iterator) + * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) + * @return A std::vector of the extracted strings from the input container of wchar_t + * characters + */ + template + ::std::vector<::std::wstring> get_wstring_vector_from_multistring(const InputIt &first, const InputIt &last) { - multistring.insert(multistring.end(), ::std::begin(wstr), ::std::end(wstr)); - multistring.push_back(L'\0'); + if (last - first < 3) + { + // it doesn't have the required 2 terminating null characters - return an empty string + return ::std::vector<::std::wstring>(1); + } + + ::std::vector<::std::wstring> strings; + walk_multistring(first, last, [&](const InputIt &string_first, const InputIt &string_last) { + strings.emplace_back(string_first, string_last); + }); + return strings; } - - // double-null-terminate the last string - multistring.push_back(L'\0'); - return multistring; - } - - /** - * @brief A translation function taking iterators referencing wchar_t characters and returns extracted individual - * std::wstring objects. The translation follows the rules for how MULTI_SZ registry value can be formatted, - * notably with embedded null characters. Note that this conversion avoids returning empty std::wstring objects - * even though the input may contain contiguous null wchar_t values - * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual - * strings - * @param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * @return A std::vector of the extracted strings from the input container of wchar_t characters - */ - template - ::std::vector<::std::wstring> get_wstring_vector_from_multistring(const InputIt& first, const InputIt& last) - { - if (last - first < 3) - { - // it doesn't have the required 2 terminating null characters - return an empty string - return ::std::vector<::std::wstring>(1); - } - - ::std::vector<::std::wstring> strings; - walk_multistring(first, last, [&](const InputIt& string_first, const InputIt& string_last) { - strings.emplace_back(string_first, string_last); - }); - return strings; - } #endif #if defined(__WIL_OBJBASE_H_) - template - void get_multistring_bytearray_from_strings_nothrow(const PCWSTR data[C], ::wil::unique_cotaskmem_array_ptr& multistring) WI_NOEXCEPT - { - constexpr uint8_t nullTermination[2]{0x00, 0x00}; - - size_t total_array_length_bytes = 0; - for (size_t i = 0; i < C; ++i) + template + void get_multistring_bytearray_from_strings_nothrow( + const PCWSTR data[C], ::wil::unique_cotaskmem_array_ptr &multistring) WI_NOEXCEPT { - total_array_length_bytes += wcslen(data[i]) * sizeof(wchar_t); - total_array_length_bytes += sizeof(wchar_t); // plus one for the null-terminator - } - total_array_length_bytes += sizeof(wchar_t); // plus one for the ending double-null-terminator + constexpr uint8_t nullTermination[2]{0x00, 0x00}; - *multistring.addressof() = static_cast(::CoTaskMemAlloc(total_array_length_bytes)); - if (!multistring.get()) - { - multistring.reset(); - return; - } - *multistring.size_address() = total_array_length_bytes; - - size_t array_offset = 0; - for (size_t i = 0; i < C; ++i) - { - const auto string_length_bytes = wcslen(data[i]) * sizeof(wchar_t); - memcpy(multistring.get() + array_offset, data[i], string_length_bytes); - array_offset += string_length_bytes; - - static_assert(sizeof(nullTermination) == sizeof(wchar_t), "null terminator must be a wchar"); - memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); - array_offset += sizeof(nullTermination); - } - - // double-null-terminate the last string - memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); - } - - /** - * @brief A translation function taking iterators referencing wchar_t characters and returns extracted individual - * wil::unique_cotaskmem_string objects. The translation follows the rules for how MULTI_SZ registry value can be - * formatted, notably with embedded null characters. Note that this conversion avoids returning empty - * wil::unique_cotaskmem_string objects even though the input may contain contiguous null wchar_t values - * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual - * strings - * @param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * @param cotaskmem_array The [out] wil::unique_cotaskmem_array_ptr to contain the array of - * strings. A wil::unique_cotaskmem_array_ptr of the extracted strings from the - * input container of wchar_t characters. An empty wil::unique_cotaskmem_array_ptr should be translated as out-of - * memory as there should always be at least one wil::unique_cotaskmem_string - */ - template - void get_cotaskmemstring_array_from_multistring_nothrow( - const InputIt& first, const InputIt& last, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& cotaskmem_array) WI_NOEXCEPT - { - if (last - first < 3) - { - // it doesn't have the required 2 terminating null characters - return an empty string - *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * 1)); - if (cotaskmem_array) + size_t total_array_length_bytes = 0; + for (size_t i = 0; i < C; ++i) { - auto new_string = ::wil::make_cotaskmem_string_nothrow(L""); - if (new_string) + total_array_length_bytes += wcslen(data[i]) * sizeof(wchar_t); + total_array_length_bytes += sizeof(wchar_t); // plus one for the null-terminator + } + total_array_length_bytes += sizeof(wchar_t); // plus one for the ending double-null-terminator + + *multistring.addressof() = static_cast(::CoTaskMemAlloc(total_array_length_bytes)); + if (!multistring.get()) + { + multistring.reset(); + return; + } + *multistring.size_address() = total_array_length_bytes; + + size_t array_offset = 0; + for (size_t i = 0; i < C; ++i) + { + const auto string_length_bytes = wcslen(data[i]) * sizeof(wchar_t); + memcpy(multistring.get() + array_offset, data[i], string_length_bytes); + array_offset += string_length_bytes; + + static_assert(sizeof(nullTermination) == sizeof(wchar_t), "null terminator must be a wchar"); + memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); + array_offset += sizeof(nullTermination); + } + + // double-null-terminate the last string + memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); + } + + /** + * @brief A translation function taking iterators referencing wchar_t characters and returns extracted + * individual wil::unique_cotaskmem_string objects. The translation follows the rules for how MULTI_SZ + * registry value can be formatted, notably with embedded null characters. Note that this conversion avoids + * returning empty wil::unique_cotaskmem_string objects even though the input may contain contiguous null + * wchar_t values + * @tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate + * into individual strings + * @param first An iterator referencing to the beginning of the target container (like a std::begin + * iterator) + * @param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) + * @param cotaskmem_array The [out] wil::unique_cotaskmem_array_ptr to contain + * the array of strings. A wil::unique_cotaskmem_array_ptr of the extracted + * strings from the input container of wchar_t characters. An empty wil::unique_cotaskmem_array_ptr should + * be translated as out-of memory as there should always be at least one wil::unique_cotaskmem_string + */ + template + void get_cotaskmemstring_array_from_multistring_nothrow( + const InputIt &first, const InputIt &last, + ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> &cotaskmem_array) WI_NOEXCEPT + { + if (last - first < 3) + { + // it doesn't have the required 2 terminating null characters - return an empty string + *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * 1)); + if (cotaskmem_array) { - *cotaskmem_array.size_address() = 1; - cotaskmem_array[0] = new_string.release(); + auto new_string = ::wil::make_cotaskmem_string_nothrow(L""); + if (new_string) + { + *cotaskmem_array.size_address() = 1; + cotaskmem_array[0] = new_string.release(); + } + else + { + // oom will return an empty array + cotaskmem_array.reset(); + } } else { // oom will return an empty array cotaskmem_array.reset(); } + return; } - else - { - // oom will return an empty array - cotaskmem_array.reset(); - } - return; - } - // we must first count the # of strings for the array - size_t arraySize = 0; - walk_multistring(first, last, [&](const InputIt&, const InputIt&) { - ++arraySize; - }); + // we must first count the # of strings for the array + size_t arraySize = 0; + walk_multistring(first, last, [&](const InputIt &, const InputIt &) { ++arraySize; }); - // allocate the array size necessary to hold all the unique_cotaskmem_strings - *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * arraySize)); - if (!cotaskmem_array) - { - // oom will return an empty array - cotaskmem_array.reset(); - return; - } - - *cotaskmem_array.size_address() = arraySize; - ZeroMemory(cotaskmem_array.data(), sizeof(PWSTR) * arraySize); - - size_t arrayOffset = 0; - walk_multistring(first, last, [&](const InputIt& string_first, const InputIt& string_last) { - FAIL_FAST_IF(arrayOffset >= arraySize); - const auto stringSize = string_last - string_first; - auto new_string = ::wil::make_cotaskmem_string_nothrow(&(*string_first), stringSize); - if (!new_string) + // allocate the array size necessary to hold all the unique_cotaskmem_strings + *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * arraySize)); + if (!cotaskmem_array) { // oom will return an empty array cotaskmem_array.reset(); return; } - cotaskmem_array[arrayOffset] = new_string.release(); - ++arrayOffset; - }); - } + + *cotaskmem_array.size_address() = arraySize; + ZeroMemory(cotaskmem_array.data(), sizeof(PWSTR) * arraySize); + + size_t arrayOffset = 0; + walk_multistring(first, last, [&](const InputIt &string_first, const InputIt &string_last) { + FAIL_FAST_IF(arrayOffset >= arraySize); + const auto stringSize = string_last - string_first; + auto new_string = ::wil::make_cotaskmem_string_nothrow(&(*string_first), stringSize); + if (!new_string) + { + // oom will return an empty array + cotaskmem_array.reset(); + return; + } + cotaskmem_array[arrayOffset] = new_string.release(); + ++arrayOffset; + }); + } #endif // #if defined(__WIL_OBJBASE_H_) - namespace reg_value_type_info - { - // supports_prepare_buffer is used to determine if the input buffer to read a registry value should be prepared - // before the first call to the registry read API - template - constexpr bool supports_prepare_buffer() WI_NOEXCEPT + namespace reg_value_type_info { - return false; - } - template - HRESULT prepare_buffer(T&) WI_NOEXCEPT - { - // no-op in the default case - return S_OK; - } + // supports_prepare_buffer is used to determine if the input buffer to read a registry value should be + // prepared before the first call to the registry read API + template constexpr bool supports_prepare_buffer() WI_NOEXCEPT + { + return false; + } + template HRESULT prepare_buffer(T &) WI_NOEXCEPT + { + // no-op in the default case + return S_OK; + } - // supports_resize_buffer_bytes is used to determine if the input buffer to read a registry value can be resized - // for those cases if the error from the registry read API indicates it needs a larger buffer - template - constexpr bool supports_resize_buffer_bytes() WI_NOEXCEPT - { - return false; - } - template - constexpr HRESULT resize_buffer_bytes(T&, DWORD) WI_NOEXCEPT - { - return E_NOTIMPL; - } + // supports_resize_buffer_bytes is used to determine if the input buffer to read a registry value can be + // resized for those cases if the error from the registry read API indicates it needs a larger buffer + template constexpr bool supports_resize_buffer_bytes() WI_NOEXCEPT + { + return false; + } + template constexpr HRESULT resize_buffer_bytes(T &, DWORD) WI_NOEXCEPT + { + return E_NOTIMPL; + } - // supports_trim_buffer is used to determine if the input buffer to read a registry value must be trimmed - // after the registry read API has successfully written into the supplied buffer - // note that currently only std::wstring requires this as it cannot have embedded nulls - template - constexpr bool supports_trim_buffer() WI_NOEXCEPT - { - return false; - } - // if called for a type that does not support trimming, will return a zero-length - template - constexpr size_t trim_buffer(T&) WI_NOEXCEPT - { - return 0; - } - - constexpr void* get_buffer(const int32_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(int32_t) WI_NOEXCEPT - { - return static_cast(sizeof(int32_t)); - } - - constexpr void* get_buffer(const uint32_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(uint32_t) WI_NOEXCEPT - { - return static_cast(sizeof(uint32_t)); - } - - constexpr void* get_buffer(const long& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(long) WI_NOEXCEPT - { - return static_cast(sizeof(long)); - } - - constexpr void* get_buffer(const unsigned long& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(unsigned long) WI_NOEXCEPT - { - return static_cast(sizeof(unsigned long)); - } - - constexpr void* get_buffer(const int64_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(int64_t) WI_NOEXCEPT - { - return static_cast(sizeof(int64_t)); - } - - constexpr void* get_buffer(const uint64_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(uint64_t) WI_NOEXCEPT - { - return static_cast(sizeof(uint64_t)); - } - - constexpr void* get_buffer(PCWSTR value) WI_NOEXCEPT - { - return const_cast(value); - } - - inline DWORD get_buffer_size_bytes(PCWSTR value) WI_NOEXCEPT - { - if (!value) + // supports_trim_buffer is used to determine if the input buffer to read a registry value must be + // trimmed after the registry read API has successfully written into the supplied buffer note that + // currently only std::wstring requires this as it cannot have embedded nulls + template constexpr bool supports_trim_buffer() WI_NOEXCEPT + { + return false; + } + // if called for a type that does not support trimming, will return a zero-length + template constexpr size_t trim_buffer(T &) WI_NOEXCEPT { return 0; } - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - return static_cast((::wcslen(value) + 1) * sizeof(wchar_t)); - } + + constexpr void *get_buffer(const int32_t &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(int32_t) WI_NOEXCEPT + { + return static_cast(sizeof(int32_t)); + } + + constexpr void *get_buffer(const uint32_t &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(uint32_t) WI_NOEXCEPT + { + return static_cast(sizeof(uint32_t)); + } + + constexpr void *get_buffer(const long &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(long) WI_NOEXCEPT + { + return static_cast(sizeof(long)); + } + + constexpr void *get_buffer(const unsigned long &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(unsigned long) WI_NOEXCEPT + { + return static_cast(sizeof(unsigned long)); + } + + constexpr void *get_buffer(const int64_t &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(int64_t) WI_NOEXCEPT + { + return static_cast(sizeof(int64_t)); + } + + constexpr void *get_buffer(const uint64_t &value) WI_NOEXCEPT + { + return const_cast(&value); + } + + constexpr DWORD get_buffer_size_bytes(uint64_t) WI_NOEXCEPT + { + return static_cast(sizeof(uint64_t)); + } + + constexpr void *get_buffer(PCWSTR value) WI_NOEXCEPT + { + return const_cast(value); + } + + inline DWORD get_buffer_size_bytes(PCWSTR value) WI_NOEXCEPT + { + if (!value) + { + return 0; + } + // including the last null buffer space in the returned buffer-size-bytes + // as the registry API we call guarantees null termination + return static_cast((::wcslen(value) + 1) * sizeof(wchar_t)); + } #if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) - inline void* get_buffer(const ::std::vector& buffer) WI_NOEXCEPT - { - return const_cast(buffer.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::vector& value) WI_NOEXCEPT - { - return static_cast(value.size()); - } - - template <> - constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::vector& value) WI_NOEXCEPT - try - { - // resize the initial vector to at least 1 byte - // this is needed so we can detect when the registry value exists - // but the value has zero-bytes - if (value.empty()) + inline void *get_buffer(const ::std::vector &buffer) WI_NOEXCEPT { - value.resize(1); + return const_cast(buffer.data()); } - // zero out the buffer if pre-allocated - for (auto& string_char : value) + + inline DWORD get_buffer_size_bytes(const ::std::vector &value) WI_NOEXCEPT { - string_char = 0x00; + return static_cast(value.size()); } - return S_OK; - } - CATCH_RETURN(); - template <> - constexpr bool supports_resize_buffer_bytes<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::std::vector& buffer, DWORD byteSize) WI_NOEXCEPT - try - { - buffer.resize(byteSize); - return S_OK; - } - CATCH_RETURN(); - - // std::vector does not implement resize_buffer_bytes - // because these support functions are only needed for set_value - // from the return of get_multistring_from_wstrings - inline void* get_buffer(const ::std::vector& value) WI_NOEXCEPT - { - return const_cast(value.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::vector& value) WI_NOEXCEPT - { - return static_cast(value.size()) * sizeof(wchar_t); - } - - template <> - constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::vector& value) WI_NOEXCEPT - { - // zero out the buffer if pre-allocated - for (auto& string_char : value) + template <> constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT { - string_char = L'\0'; + return true; + } + inline HRESULT prepare_buffer(::std::vector &value) WI_NOEXCEPT + try + { + // resize the initial vector to at least 1 byte + // this is needed so we can detect when the registry value exists + // but the value has zero-bytes + if (value.empty()) + { + value.resize(1); + } + // zero out the buffer if pre-allocated + for (auto &string_char : value) + { + string_char = 0x00; + } + return S_OK; + } + CATCH_RETURN(); + + template <> constexpr bool supports_resize_buffer_bytes<::std::vector>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::std::vector &buffer, DWORD byteSize) WI_NOEXCEPT + try + { + buffer.resize(byteSize); + return S_OK; + } + CATCH_RETURN(); + + // std::vector does not implement resize_buffer_bytes + // because these support functions are only needed for set_value + // from the return of get_multistring_from_wstrings + inline void *get_buffer(const ::std::vector &value) WI_NOEXCEPT + { + return const_cast(value.data()); + } + + inline DWORD get_buffer_size_bytes(const ::std::vector &value) WI_NOEXCEPT + { + return static_cast(value.size()) * sizeof(wchar_t); + } + + template <> constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT + { + return true; + } + inline HRESULT prepare_buffer(::std::vector &value) WI_NOEXCEPT + { + // zero out the buffer if pre-allocated + for (auto &string_char : value) + { + string_char = L'\0'; + } + return S_OK; } - return S_OK; - } #endif #if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) - inline void* get_buffer(const ::std::wstring& string) WI_NOEXCEPT - { - return const_cast(string.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::wstring& string) WI_NOEXCEPT - { - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - return static_cast((string.size() + 1) * sizeof(wchar_t)); - } - - template <> - constexpr bool supports_prepare_buffer<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::wstring& string) WI_NOEXCEPT - { - // zero out the buffer if pre-allocated - for (auto& string_char : string) + inline void *get_buffer(const ::std::wstring &string) WI_NOEXCEPT { - string_char = L'\0'; + return const_cast(string.data()); } - return S_OK; - } - template <> - constexpr bool supports_resize_buffer_bytes<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::std::wstring& string, DWORD byteSize) WI_NOEXCEPT - try - { - string.resize(byteSize / sizeof(wchar_t)); - return S_OK; - } - CATCH_RETURN(); - - template <> - constexpr bool supports_trim_buffer<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline size_t trim_buffer(::std::wstring& buffer) WI_NOEXCEPT - { - // remove any embedded null characters - const auto offset = buffer.find_first_of(L'\0'); - if (offset != ::std::wstring::npos) + inline DWORD get_buffer_size_bytes(const ::std::wstring &string) WI_NOEXCEPT { - buffer.resize(offset); + // including the last null buffer space in the returned buffer-size-bytes + // as the registry API we call guarantees null termination + return static_cast((string.size() + 1) * sizeof(wchar_t)); + } + + template <> constexpr bool supports_prepare_buffer<::std::wstring>() WI_NOEXCEPT + { + return true; + } + inline HRESULT prepare_buffer(::std::wstring &string) WI_NOEXCEPT + { + // zero out the buffer if pre-allocated + for (auto &string_char : string) + { + string_char = L'\0'; + } + return S_OK; + } + + template <> constexpr bool supports_resize_buffer_bytes<::std::wstring>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::std::wstring &string, DWORD byteSize) WI_NOEXCEPT + try + { + string.resize(byteSize / sizeof(wchar_t)); + return S_OK; + } + CATCH_RETURN(); + + template <> constexpr bool supports_trim_buffer<::std::wstring>() WI_NOEXCEPT + { + return true; + } + inline size_t trim_buffer(::std::wstring &buffer) WI_NOEXCEPT + { + // remove any embedded null characters + const auto offset = buffer.find_first_of(L'\0'); + if (offset != ::std::wstring::npos) + { + buffer.resize(offset); + } + return buffer.size(); } - return buffer.size(); - } #endif #if defined(__WIL_OLEAUTO_H_) - inline void* get_buffer(const BSTR& value) WI_NOEXCEPT - { - return value; - } - - inline DWORD get_buffer_size_bytes(const BSTR& value) WI_NOEXCEPT - { - auto length = ::SysStringLen(value); - if (length > 0) + inline void *get_buffer(const BSTR &value) WI_NOEXCEPT { - // SysStringLen does not count the null-terminator - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - length += 1; + return value; } - return length * sizeof(WCHAR); - } - template <> - constexpr bool supports_prepare_buffer() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const BSTR& value) WI_NOEXCEPT - { - if (value) + inline DWORD get_buffer_size_bytes(const BSTR &value) WI_NOEXCEPT { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value, get_buffer_size_bytes(value) / sizeof(WCHAR))) + auto length = ::SysStringLen(value); + if (length > 0) { - string_char = L'\0'; + // SysStringLen does not count the null-terminator + // including the last null buffer space in the returned buffer-size-bytes + // as the registry API we call guarantees null termination + length += 1; } - } - return S_OK; - } - - template <> - constexpr bool supports_resize_buffer_bytes() WI_NOEXCEPT - { - return true; - } - // transferringOwnership is only set to false if this is a 'shallow' copy of the BSTR - // and the caller maintained ownership of the original BSTR. - inline HRESULT resize_buffer_bytes(BSTR& string, DWORD byteSize, bool transferringOwnership = true) WI_NOEXCEPT - { - // copy the original BSTR to copy from later if needed - const BSTR original_string = string; - const DWORD original_string_length = string == nullptr ? 0 : ::SysStringLen(string); - - // SysStringLen doesn't count the null-terminator, but our buffer size does - const bool original_string_length_too_small = (original_string_length + 1) < byteSize / sizeof(WCHAR); - if (original_string_length_too_small) - { - // pass a null BSTR value because SysAllocStringLen will copy the contents of the original BSTR, - // but in this case it's not long enough to copy the new length to be allocated - string = nullptr; + return length * sizeof(WCHAR); } - // convert bytes to length (number of WCHAR's) - DWORD length_to_alloc = byteSize / sizeof(WCHAR); - // SysAllocStringLen adds a null, so subtract a wchar_t from the input length - length_to_alloc = length_to_alloc > 0 ? length_to_alloc - 1 : length_to_alloc; - const BSTR new_bstr{::SysAllocStringLen(string, length_to_alloc)}; - RETURN_IF_NULL_ALLOC(new_bstr); - - // copy back the original BSTR if it was too small for SysAllocStringLen - // also assuming that both lengths are greater than zero - const DWORD sourceLengthToCopy = original_string_length < length_to_alloc ? original_string_length : length_to_alloc; - if (sourceLengthToCopy > 0 && original_string_length_too_small) + template <> constexpr bool supports_prepare_buffer() WI_NOEXCEPT { - ::memcpy_s(new_bstr, length_to_alloc * sizeof(WCHAR), original_string, sourceLengthToCopy * sizeof(WCHAR)); + return true; } - - // if not transferring ownership, the caller will still own the original BSTR - if (transferringOwnership) + inline HRESULT prepare_buffer(const BSTR &value) WI_NOEXCEPT { - ::SysFreeString(string); - } - - string = new_bstr; - return S_OK; - } - - inline void* get_buffer(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - return value.get(); - } - - inline DWORD get_buffer_size_bytes(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - return get_buffer_size_bytes(value.get()); - } - - template <> - constexpr bool supports_prepare_buffer<::wil::unique_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - if (value) - { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) + if (value) { - string_char = L'\0'; + // zero out the buffer if pre-allocated + for (auto &string_char : ::wil::make_range(value, get_buffer_size_bytes(value) / sizeof(WCHAR))) + { + string_char = L'\0'; + } } + return S_OK; } - return S_OK; - } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::unique_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::unique_bstr& string, DWORD byteSize) WI_NOEXCEPT - { - BSTR temp_bstr = string.get(); + template <> constexpr bool supports_resize_buffer_bytes() WI_NOEXCEPT + { + return true; + } + // transferringOwnership is only set to false if this is a 'shallow' copy of the BSTR + // and the caller maintained ownership of the original BSTR. + inline HRESULT resize_buffer_bytes(BSTR &string, DWORD byteSize, + bool transferringOwnership = true) WI_NOEXCEPT + { + // copy the original BSTR to copy from later if needed + const BSTR original_string = string; + const DWORD original_string_length = string == nullptr ? 0 : ::SysStringLen(string); - // not transferring ownership of the BSTR within 'string' to resize_buffer_bytes() - // resize_buffer_bytes() will overwrite temp_bstr with a newly-allocated BSTR - constexpr bool transferringOwnership = false; - RETURN_IF_FAILED(resize_buffer_bytes(temp_bstr, byteSize, transferringOwnership)); + // SysStringLen doesn't count the null-terminator, but our buffer size does + const bool original_string_length_too_small = + (original_string_length + 1) < byteSize / sizeof(WCHAR); + if (original_string_length_too_small) + { + // pass a null BSTR value because SysAllocStringLen will copy the contents of the original BSTR, + // but in this case it's not long enough to copy the new length to be allocated + string = nullptr; + } - // if succeeded in creating a new BSTR, move ownership of the new BSTR into string - string.reset(temp_bstr); - return S_OK; - } + // convert bytes to length (number of WCHAR's) + DWORD length_to_alloc = byteSize / sizeof(WCHAR); + // SysAllocStringLen adds a null, so subtract a wchar_t from the input length + length_to_alloc = length_to_alloc > 0 ? length_to_alloc - 1 : length_to_alloc; + const BSTR new_bstr{::SysAllocStringLen(string, length_to_alloc)}; + RETURN_IF_NULL_ALLOC(new_bstr); + + // copy back the original BSTR if it was too small for SysAllocStringLen + // also assuming that both lengths are greater than zero + const DWORD sourceLengthToCopy = + original_string_length < length_to_alloc ? original_string_length : length_to_alloc; + if (sourceLengthToCopy > 0 && original_string_length_too_small) + { + ::memcpy_s(new_bstr, length_to_alloc * sizeof(WCHAR), original_string, + sourceLengthToCopy * sizeof(WCHAR)); + } + + // if not transferring ownership, the caller will still own the original BSTR + if (transferringOwnership) + { + ::SysFreeString(string); + } + + string = new_bstr; + return S_OK; + } + + inline void *get_buffer(const ::wil::unique_bstr &value) WI_NOEXCEPT + { + return value.get(); + } + + inline DWORD get_buffer_size_bytes(const ::wil::unique_bstr &value) WI_NOEXCEPT + { + return get_buffer_size_bytes(value.get()); + } + + template <> constexpr bool supports_prepare_buffer<::wil::unique_bstr>() WI_NOEXCEPT + { + return true; + } + inline HRESULT prepare_buffer(const ::wil::unique_bstr &value) WI_NOEXCEPT + { + if (value) + { + // zero out the buffer if pre-allocated + for (auto &string_char : + ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) + { + string_char = L'\0'; + } + } + return S_OK; + } + + template <> constexpr bool supports_resize_buffer_bytes<::wil::unique_bstr>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::unique_bstr &string, DWORD byteSize) WI_NOEXCEPT + { + BSTR temp_bstr = string.get(); + + // not transferring ownership of the BSTR within 'string' to resize_buffer_bytes() + // resize_buffer_bytes() will overwrite temp_bstr with a newly-allocated BSTR + constexpr bool transferringOwnership = false; + RETURN_IF_FAILED(resize_buffer_bytes(temp_bstr, byteSize, transferringOwnership)); + + // if succeeded in creating a new BSTR, move ownership of the new BSTR into string + string.reset(temp_bstr); + return S_OK; + } #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OLEAUTO_H_STL) - inline void* get_buffer(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - return value.get(); - } - - inline DWORD get_buffer_size_bytes(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - return get_buffer_size_bytes(value.get()); - } - - template <> - constexpr bool supports_prepare_buffer<::wil::shared_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - if (value) + inline void *get_buffer(const ::wil::shared_bstr &value) WI_NOEXCEPT { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) - { - string_char = L'\0'; - } + return value.get(); } - return S_OK; - } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::shared_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::shared_bstr& string, DWORD byteSize) WI_NOEXCEPT - { - BSTR temp_bstr = string.get(); + inline DWORD get_buffer_size_bytes(const ::wil::shared_bstr &value) WI_NOEXCEPT + { + return get_buffer_size_bytes(value.get()); + } - // not transferring ownership of the BSTR within 'string' to resize_buffer_bytes() - // resize_buffer_bytes() will overwrite temp_bstr with a newly-allocated BSTR - constexpr bool transferringOwnership = false; - RETURN_IF_FAILED(resize_buffer_bytes(temp_bstr, byteSize, transferringOwnership)); + template <> constexpr bool supports_prepare_buffer<::wil::shared_bstr>() WI_NOEXCEPT + { + return true; + } + inline HRESULT prepare_buffer(const ::wil::shared_bstr &value) WI_NOEXCEPT + { + if (value) + { + // zero out the buffer if pre-allocated + for (auto &string_char : + ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) + { + string_char = L'\0'; + } + } + return S_OK; + } - // if succeeded in creating a new BSTR, move ownership of the new BSTR into string - string.reset(temp_bstr); - return S_OK; - } + template <> constexpr bool supports_resize_buffer_bytes<::wil::shared_bstr>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::shared_bstr &string, DWORD byteSize) WI_NOEXCEPT + { + BSTR temp_bstr = string.get(); + + // not transferring ownership of the BSTR within 'string' to resize_buffer_bytes() + // resize_buffer_bytes() will overwrite temp_bstr with a newly-allocated BSTR + constexpr bool transferringOwnership = false; + RETURN_IF_FAILED(resize_buffer_bytes(temp_bstr, byteSize, transferringOwnership)); + + // if succeeded in creating a new BSTR, move ownership of the new BSTR into string + string.reset(temp_bstr); + return S_OK; + } #endif // #if defined(__WIL_OLEAUTO_H_STL) #if defined(__WIL_OBJBASE_H_) - inline void* get_buffer(const ::wil::unique_cotaskmem_string& value) WI_NOEXCEPT - { - return value.get(); - } + inline void *get_buffer(const ::wil::unique_cotaskmem_string &value) WI_NOEXCEPT + { + return value.get(); + } - constexpr DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_string&) WI_NOEXCEPT - { - // wil::unique_cotaskmem_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } + constexpr DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_string &) WI_NOEXCEPT + { + // wil::unique_cotaskmem_string does not intrinsically track its internal buffer size + // thus the caller must track the buffer size it requested to be allocated + return 0; + } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::unique_cotaskmem_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::unique_cotaskmem_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(wchar_t); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); + template <> constexpr bool supports_resize_buffer_bytes<::wil::unique_cotaskmem_string>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::unique_cotaskmem_string &string, DWORD byteSize) WI_NOEXCEPT + { + // convert bytes to length (number of WCHAR's) + size_t length = byteSize / sizeof(wchar_t); + // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from + // the input length + length = length > 0 ? length - 1 : length; + auto new_string = + ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); + RETURN_IF_NULL_ALLOC(new_string.get()); - string = ::wistd::move(new_string); - return S_OK; - } + string = ::wistd::move(new_string); + return S_OK; + } - inline void* get_buffer(const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return value.get(); - } + inline void *get_buffer(const ::wil::unique_cotaskmem_array_ptr &value) WI_NOEXCEPT + { + return value.get(); + } - inline DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return static_cast(value.size()); - } + inline DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_array_ptr &value) WI_NOEXCEPT + { + return static_cast(value.size()); + } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::unique_cotaskmem_array_ptr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::unique_cotaskmem_array_ptr& arrayValue, DWORD byteSize) WI_NOEXCEPT - { - ::wil::unique_cotaskmem_array_ptr tempValue; - *tempValue.addressof() = static_cast(::CoTaskMemAlloc(byteSize)); - RETURN_IF_NULL_ALLOC(tempValue.get()); - *tempValue.size_address() = byteSize; + template <> + constexpr bool supports_resize_buffer_bytes<::wil::unique_cotaskmem_array_ptr>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::unique_cotaskmem_array_ptr &arrayValue, + DWORD byteSize) WI_NOEXCEPT + { + ::wil::unique_cotaskmem_array_ptr tempValue; + *tempValue.addressof() = static_cast(::CoTaskMemAlloc(byteSize)); + RETURN_IF_NULL_ALLOC(tempValue.get()); + *tempValue.size_address() = byteSize; - const auto bytesToCopy = arrayValue.size() < byteSize ? arrayValue.size() : byteSize; - CopyMemory(tempValue.get(), arrayValue.get(), bytesToCopy); + const auto bytesToCopy = arrayValue.size() < byteSize ? arrayValue.size() : byteSize; + CopyMemory(tempValue.get(), arrayValue.get(), bytesToCopy); - arrayValue = ::wistd::move(tempValue); - return S_OK; - } + arrayValue = ::wistd::move(tempValue); + return S_OK; + } #endif // #if defined(__WIL_OBJBASE_H_) #if defined(__WIL_OBJBASE_H_STL) - inline void* get_buffer(const ::wil::shared_cotaskmem_string& value) WI_NOEXCEPT - { - return value.get(); - } + inline void *get_buffer(const ::wil::shared_cotaskmem_string &value) WI_NOEXCEPT + { + return value.get(); + } - constexpr DWORD get_buffer_size_bytes(const ::wil::shared_cotaskmem_string&) WI_NOEXCEPT - { - // wil::shared_cotaskmem_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } + constexpr DWORD get_buffer_size_bytes(const ::wil::shared_cotaskmem_string &) WI_NOEXCEPT + { + // wil::shared_cotaskmem_string does not intrinsically track its internal buffer size + // thus the caller must track the buffer size it requested to be allocated + return 0; + } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::shared_cotaskmem_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::shared_cotaskmem_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(WCHAR); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); + template <> constexpr bool supports_resize_buffer_bytes<::wil::shared_cotaskmem_string>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::shared_cotaskmem_string &string, DWORD byteSize) WI_NOEXCEPT + { + // convert bytes to length (number of WCHAR's) + size_t length = byteSize / sizeof(WCHAR); + // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from + // the input length + length = length > 0 ? length - 1 : length; + auto new_string = + ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); + RETURN_IF_NULL_ALLOC(new_string.get()); - string = ::wistd::move(new_string); - return S_OK; - } + string = ::wistd::move(new_string); + return S_OK; + } #endif // #if defined(__WIL_OBJBASE_H_STL) - inline void* get_buffer(const ::wil::unique_process_heap_string& value) WI_NOEXCEPT - { - return value.get(); - } + inline void *get_buffer(const ::wil::unique_process_heap_string &value) WI_NOEXCEPT + { + return value.get(); + } - constexpr DWORD get_buffer_size_bytes(const ::wil::unique_process_heap_string&) WI_NOEXCEPT - { - // wil::unique_process_heap_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } + constexpr DWORD get_buffer_size_bytes(const ::wil::unique_process_heap_string &) WI_NOEXCEPT + { + // wil::unique_process_heap_string does not intrinsically track its internal buffer size + // thus the caller must track the buffer size it requested to be allocated + return 0; + } - template <> - constexpr bool supports_resize_buffer_bytes<::wil::unique_process_heap_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer_bytes(::wil::unique_process_heap_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(wchar_t); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_process_heap_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); + template <> constexpr bool supports_resize_buffer_bytes<::wil::unique_process_heap_string>() WI_NOEXCEPT + { + return true; + } + inline HRESULT resize_buffer_bytes(::wil::unique_process_heap_string &string, + DWORD byteSize) WI_NOEXCEPT + { + // convert bytes to length (number of WCHAR's) + size_t length = byteSize / sizeof(wchar_t); + // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from + // the input length + length = length > 0 ? length - 1 : length; + auto new_string = + ::wil::make_unique_string_nothrow<::wil::unique_process_heap_string>(string.get(), length); + RETURN_IF_NULL_ALLOC(new_string.get()); - string = ::wistd::move(new_string); - return S_OK; - } + string = ::wistd::move(new_string); + return S_OK; + } - // constexpr expressions to determining the get* and set* registry value types - // for all supported types T to read/write values - template - DWORD get_value_type() WI_NOEXCEPT - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_type"); - } + // constexpr expressions to determining the get* and set* registry value types + // for all supported types T to read/write values + template DWORD get_value_type() WI_NOEXCEPT + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_type"); + } - template - DWORD set_value_type() WI_NOEXCEPT - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for set_value_type"); - } + template DWORD set_value_type() WI_NOEXCEPT + { + static_assert(sizeof(T) != sizeof(T), "Unsupported type for set_value_type"); + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_DWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_DWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_DWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_DWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_DWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_DWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_DWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_DWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_QWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_QWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_QWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_QWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_QWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_QWORD; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_QWORD); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_QWORD; + } - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) - template <> - constexpr DWORD get_value_type<::std::wstring>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } + template <> constexpr DWORD get_value_type<::std::wstring>() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #endif #if defined(__WIL_OLEAUTO_H_) - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - template <> - constexpr DWORD get_value_type<::wil::unique_bstr>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } + template <> constexpr DWORD get_value_type() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } + template <> constexpr DWORD get_value_type<::wil::unique_bstr>() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OLEAUTO_H_STL) - template <> - constexpr DWORD get_value_type<::wil::shared_bstr>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } + template <> constexpr DWORD get_value_type<::wil::shared_bstr>() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #endif // #if defined(__WIL_OLEAUTO_H_STL) #if defined(__WIL_OBJBASE_H_) - template <> - constexpr DWORD get_value_type<::wil::unique_cotaskmem_string>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } + template <> constexpr DWORD get_value_type<::wil::unique_cotaskmem_string>() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #endif // defined(__WIL_OBJBASE_H_) #if defined(__WIL_OBJBASE_H_STL) - template <> - constexpr DWORD get_value_type<::wil::shared_cotaskmem_string>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } + template <> constexpr DWORD get_value_type<::wil::shared_cotaskmem_string>() WI_NOEXCEPT + { + return get_value_flags_from_value_type(REG_SZ); + } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } + template <> constexpr DWORD set_value_type() WI_NOEXCEPT + { + return REG_SZ; + } #endif // #if defined(__WIL_OBJBASE_H_STL) - } // namespace reg_value_type_info + } // namespace reg_value_type_info - template - class reg_view_t - { - public: - explicit reg_view_t(HKEY key) WI_NOEXCEPT : m_key(key) + template class reg_view_t { - } - ~reg_view_t() WI_NOEXCEPT = default; - reg_view_t(const reg_view_t&) = delete; - reg_view_t& operator=(const reg_view_t&) = delete; - reg_view_t(reg_view_t&&) = delete; - reg_view_t& operator=(reg_view_t&&) = delete; - - typename err_policy::result open_key( - _In_opt_ _In_opt_ PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const - { - constexpr DWORD zero_options{0}; - return err_policy::HResult( - HRESULT_FROM_WIN32(::RegOpenKeyExW(m_key, subKey, zero_options, get_access_flags(access), hkey))); - } - - typename err_policy::result create_key(PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const - { - *hkey = nullptr; - - constexpr DWORD zero_reserved{0}; - constexpr PWSTR null_class{nullptr}; - constexpr DWORD zero_options{0}; - constexpr SECURITY_ATTRIBUTES* null_security_attributes{nullptr}; - DWORD disposition{0}; - return err_policy::HResult(HRESULT_FROM_WIN32(::RegCreateKeyExW( - m_key, subKey, zero_reserved, null_class, zero_options, get_access_flags(access), null_security_attributes, hkey, &disposition))); - } - - typename err_policy::result delete_tree(_In_opt_ PCWSTR sub_key) const - { - auto hr = HRESULT_FROM_WIN32(::RegDeleteTreeW(m_key, sub_key)); - if (::wil::reg::is_registry_not_found(hr)) + public: + explicit reg_view_t(HKEY key) WI_NOEXCEPT : m_key(key) { - hr = S_OK; } - return err_policy::HResult(hr); - } + ~reg_view_t() WI_NOEXCEPT = default; + reg_view_t(const reg_view_t &) = delete; + reg_view_t &operator=(const reg_view_t &) = delete; + reg_view_t(reg_view_t &&) = delete; + reg_view_t &operator=(reg_view_t &&) = delete; - typename err_policy::result delete_value(_In_opt_ PCWSTR value_name) const - { - return err_policy::HResult(HRESULT_FROM_WIN32(::RegDeleteValueW(m_key, value_name))); - } - - template - typename err_policy::result get_value( - _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, R& return_value, DWORD type = reg_value_type_info::get_value_type()) const - { - return get_value_with_type(subkey, value_name, return_value, type); - } - - // typename D supports unsigned 32-bit values; i.e. allows the caller to pass a DWORD* as well as uint32_t* - template || wistd::is_same_v>* = nullptr> - typename err_policy::result get_value_char_array( - _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], DWORD type, _Out_opt_ DwordType* requiredBytes) const - { - constexpr DwordType zero_value{0ul}; - ::wil::assign_to_opt_param(requiredBytes, zero_value); - DWORD data_size_bytes{Length * sizeof(WCHAR)}; - const auto hr = HRESULT_FROM_WIN32(::RegGetValueW( - m_key, subkey, value_name, ::wil::reg::reg_view_details::get_value_flags_from_value_type(type), nullptr, return_value, &data_size_bytes)); - if (SUCCEEDED(hr) || ::wil::reg::is_registry_buffer_too_small(hr)) + typename err_policy::result open_key(_In_opt_ _In_opt_ PCWSTR subKey, _Out_ HKEY *hkey, + ::wil::reg::key_access access = ::wil::reg::key_access::read) const { - const DwordType updated_value{data_size_bytes}; - ::wil::assign_to_opt_param(requiredBytes, updated_value); + constexpr DWORD zero_options{0}; + return err_policy::HResult(HRESULT_FROM_WIN32( + ::RegOpenKeyExW(m_key, subKey, zero_options, get_access_flags(access), hkey))); + } + + typename err_policy::result create_key( + PCWSTR subKey, _Out_ HKEY *hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const + { + *hkey = nullptr; + + constexpr DWORD zero_reserved{0}; + constexpr PWSTR null_class{nullptr}; + constexpr DWORD zero_options{0}; + constexpr SECURITY_ATTRIBUTES *null_security_attributes{nullptr}; + DWORD disposition{0}; + return err_policy::HResult(HRESULT_FROM_WIN32( + ::RegCreateKeyExW(m_key, subKey, zero_reserved, null_class, zero_options, + get_access_flags(access), null_security_attributes, hkey, &disposition))); + } + + typename err_policy::result delete_tree(_In_opt_ PCWSTR sub_key) const + { + auto hr = HRESULT_FROM_WIN32(::RegDeleteTreeW(m_key, sub_key)); + if (::wil::reg::is_registry_not_found(hr)) + { + hr = S_OK; + } + return err_policy::HResult(hr); + } + + typename err_policy::result delete_value(_In_opt_ PCWSTR value_name) const + { + return err_policy::HResult(HRESULT_FROM_WIN32(::RegDeleteValueW(m_key, value_name))); + } + + template + typename err_policy::result get_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + R &return_value, + DWORD type = reg_value_type_info::get_value_type()) const + { + return get_value_with_type(subkey, value_name, return_value, type); + } + + // typename D supports unsigned 32-bit values; i.e. allows the caller to pass a DWORD* as well as + // uint32_t* + template || + wistd::is_same_v> * = nullptr> + typename err_policy::result get_value_char_array(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + WCHAR (&return_value)[Length], DWORD type, + _Out_opt_ DwordType *requiredBytes) const + { + constexpr DwordType zero_value{0ul}; + ::wil::assign_to_opt_param(requiredBytes, zero_value); + DWORD data_size_bytes{Length * sizeof(WCHAR)}; + const auto hr = HRESULT_FROM_WIN32(::RegGetValueW( + m_key, subkey, value_name, ::wil::reg::reg_view_details::get_value_flags_from_value_type(type), + nullptr, return_value, &data_size_bytes)); + if (SUCCEEDED(hr) || ::wil::reg::is_registry_buffer_too_small(hr)) + { + const DwordType updated_value{data_size_bytes}; + ::wil::assign_to_opt_param(requiredBytes, updated_value); + } + return err_policy::HResult(hr); } - return err_policy::HResult(hr); - } #if (WIL_USE_STL && (__cpp_lib_optional >= 201606L)) || defined(WIL_DOXYGEN) - // intended for err_exception_policy as err_returncode_policy will not get an error code - template - ::std::optional try_get_value( - _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, DWORD type = reg_value_type_info::get_value_type()) const - { - R value{}; - const auto hr = get_value_with_type(subkey, value_name, value, type); - if (SUCCEEDED(hr)) + // intended for err_exception_policy as err_returncode_policy will not get an error code + template + ::std::optional try_get_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + DWORD type = reg_value_type_info::get_value_type()) const { - return ::std::optional(::wistd::move(value)); - } + R value{}; + const auto hr = + get_value_with_type(subkey, value_name, value, type); + if (SUCCEEDED(hr)) + { + return ::std::optional(::wistd::move(value)); + } - if (::wil::reg::is_registry_not_found(hr)) - { + if (::wil::reg::is_registry_not_found(hr)) + { + return ::std::nullopt; + } + + // throw if exception policy + err_policy::HResult(hr); return ::std::nullopt; } - - // throw if exception policy - err_policy::HResult(hr); - return ::std::nullopt; - } #endif - template - typename err_policy::result set_value( - _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const R& value, DWORD type = reg_value_type_info::set_value_type()) const - { - return set_value_with_type(subkey, value_name, value, type); - } - - private: - const HKEY m_key{}; - - template - typename err_policy::result set_value_with_type(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const R& value, DWORD type) const - { - return err_policy::HResult(HRESULT_FROM_WIN32(::RegSetKeyValueW( - m_key, - subkey, - value_name, - type, - static_cast(reg_value_type_info::get_buffer(value)), - reg_value_type_info::get_buffer_size_bytes(value)))); - } - - template - typename get_value_with_type_policy::result get_value_with_type( - _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, R& return_value, DWORD type = reg_value_type_info::get_value_type()) const - { - if -#if defined(__cpp_if_constexpr) - constexpr -#endif - (reg_value_type_info::supports_prepare_buffer()) - + template + typename err_policy::result set_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + const R &value, + DWORD type = reg_value_type_info::set_value_type()) const { - const auto prepare_buffer_hr = reg_value_type_info::prepare_buffer(return_value); - if (FAILED(prepare_buffer_hr)) - { - return get_value_with_type_policy::HResult(prepare_buffer_hr); - } + return set_value_with_type(subkey, value_name, value, type); } - // get_buffer_size_bytes should include the null terminator when used for strings. - DWORD bytes_allocated{reg_value_type_info::get_buffer_size_bytes(return_value)}; - HRESULT get_value_hresult = S_OK; - for (;;) - { - constexpr DWORD* null_type{nullptr}; - DWORD data_size_bytes{bytes_allocated}; - get_value_hresult = HRESULT_FROM_WIN32(::RegGetValueW( - m_key, - subkey, - value_name, - get_value_flags_from_value_type(type), - null_type, - reg_value_type_info::get_buffer(return_value), - &data_size_bytes)); + private: + const HKEY m_key{}; - // some return types we can grow as needed - e.g. when writing to a std::wstring - // only compile and resize_buffer for those types that support dynamically growing the buffer + template + typename err_policy::result set_value_with_type(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, + const R &value, DWORD type) const + { + return err_policy::HResult(HRESULT_FROM_WIN32(::RegSetKeyValueW( + m_key, subkey, value_name, type, static_cast(reg_value_type_info::get_buffer(value)), + reg_value_type_info::get_buffer_size_bytes(value)))); + } + + template + typename get_value_with_type_policy::result get_value_with_type( + _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, R &return_value, + DWORD type = reg_value_type_info::get_value_type()) const + { if #if defined(__cpp_if_constexpr) constexpr #endif - (reg_value_type_info::supports_resize_buffer_bytes()) + (reg_value_type_info::supports_prepare_buffer()) + { - // Attempt to grow the buffer with the data_size_bytes returned from GetRegValueW - // GetRegValueW will indicate the caller allocate the returned number of bytes in one of two cases: - // 1. returns ERROR_MORE_DATA - // 2. returns ERROR_SUCCESS when we gave it a nullptr for the out buffer - const bool shouldReallocate = - (::wil::reg::is_registry_buffer_too_small(get_value_hresult)) || - (SUCCEEDED(get_value_hresult) && (reg_value_type_info::get_buffer(return_value) == nullptr) && - (data_size_bytes > 0)); - if (shouldReallocate) + const auto prepare_buffer_hr = reg_value_type_info::prepare_buffer(return_value); + if (FAILED(prepare_buffer_hr)) { - // verify if resize_buffer succeeded allocation - const auto resize_buffer_hr = reg_value_type_info::resize_buffer_bytes(return_value, data_size_bytes); - if (FAILED(resize_buffer_hr)) - { - // if resize fails, return this error back to the caller - return get_value_with_type_policy::HResult(resize_buffer_hr); - } - - // if it resize succeeds, continue the for loop to try again - bytes_allocated = data_size_bytes; - continue; + return get_value_with_type_policy::HResult(prepare_buffer_hr); } + } - // if the RegGetValueW call succeeded with a non-null [out] param, - // and the type supports resize_buffer_bytes - // and the bytes we allocated don't match data_size_bytes returned from RegGetValueW - // resize the buffer to match what RegGetValueW returned - if (SUCCEEDED(get_value_hresult)) + // get_buffer_size_bytes should include the null terminator when used for strings. + DWORD bytes_allocated{reg_value_type_info::get_buffer_size_bytes(return_value)}; + HRESULT get_value_hresult = S_OK; + for (;;) + { + constexpr DWORD *null_type{nullptr}; + DWORD data_size_bytes{bytes_allocated}; + get_value_hresult = HRESULT_FROM_WIN32( + ::RegGetValueW(m_key, subkey, value_name, get_value_flags_from_value_type(type), null_type, + reg_value_type_info::get_buffer(return_value), &data_size_bytes)); + + // some return types we can grow as needed - e.g. when writing to a std::wstring + // only compile and resize_buffer for those types that support dynamically growing the buffer + if +#if defined(__cpp_if_constexpr) + constexpr +#endif + (reg_value_type_info::supports_resize_buffer_bytes()) { - const auto current_byte_size = reg_value_type_info::get_buffer_size_bytes(return_value); - if (current_byte_size != data_size_bytes) + // Attempt to grow the buffer with the data_size_bytes returned from GetRegValueW + // GetRegValueW will indicate the caller allocate the returned number of bytes in one of two + // cases: + // 1. returns ERROR_MORE_DATA + // 2. returns ERROR_SUCCESS when we gave it a nullptr for the out buffer + const bool shouldReallocate = + (::wil::reg::is_registry_buffer_too_small(get_value_hresult)) || + (SUCCEEDED(get_value_hresult) && + (reg_value_type_info::get_buffer(return_value) == nullptr) && (data_size_bytes > 0)); + if (shouldReallocate) { - // verify if resize_buffer_bytes succeeded allocation - const auto resize_buffer_hr = reg_value_type_info::resize_buffer_bytes(return_value, data_size_bytes); + // verify if resize_buffer succeeded allocation + const auto resize_buffer_hr = + reg_value_type_info::resize_buffer_bytes(return_value, data_size_bytes); if (FAILED(resize_buffer_hr)) { // if resize fails, return this error back to the caller return get_value_with_type_policy::HResult(resize_buffer_hr); } + + // if it resize succeeds, continue the for loop to try again + bytes_allocated = data_size_bytes; + continue; } + + // if the RegGetValueW call succeeded with a non-null [out] param, + // and the type supports resize_buffer_bytes + // and the bytes we allocated don't match data_size_bytes returned from RegGetValueW + // resize the buffer to match what RegGetValueW returned + if (SUCCEEDED(get_value_hresult)) + { + const auto current_byte_size = reg_value_type_info::get_buffer_size_bytes(return_value); + if (current_byte_size != data_size_bytes) + { + // verify if resize_buffer_bytes succeeded allocation + const auto resize_buffer_hr = + reg_value_type_info::resize_buffer_bytes(return_value, data_size_bytes); + if (FAILED(resize_buffer_hr)) + { + // if resize fails, return this error back to the caller + return get_value_with_type_policy::HResult(resize_buffer_hr); + } + } + } + } + + // we don't need to reallocate and retry the call to RegGetValueW so breaking out of the loop + break; + } + + // some types (generally string types) require trimming its internal buffer after RegGetValueW + // successfully wrote into its buffer + if +#if defined(__cpp_if_constexpr) + constexpr +#endif + (reg_value_type_info::supports_trim_buffer()) + + { + if (SUCCEEDED(get_value_hresult)) + { + reg_value_type_info::trim_buffer(return_value); } } - // we don't need to reallocate and retry the call to RegGetValueW so breaking out of the loop - break; + return get_value_with_type_policy::HResult(get_value_hresult); } + }; - // some types (generally string types) require trimming its internal buffer after RegGetValueW successfully wrote into its buffer - if -#if defined(__cpp_if_constexpr) - constexpr -#endif - (reg_value_type_info::supports_trim_buffer()) - - { - if (SUCCEEDED(get_value_hresult)) - { - reg_value_type_info::trim_buffer(return_value); - } - } - - return get_value_with_type_policy::HResult(get_value_hresult); - } - }; - - using reg_view_nothrow = ::wil::reg::reg_view_details::reg_view_t<::wil::err_returncode_policy>; + using reg_view_nothrow = ::wil::reg::reg_view_details::reg_view_t<::wil::err_returncode_policy>; #if defined(WIL_ENABLE_EXCEPTIONS) - using reg_view = ::wil::reg::reg_view_details::reg_view_t<::wil::err_exception_policy>; + using reg_view = ::wil::reg::reg_view_details::reg_view_t<::wil::err_exception_policy>; #endif // #if defined(WIL_ENABLE_EXCEPTIONS) - } // namespace reg_view_details - /// @endcond + } // namespace reg_view_details + /// @endcond - /// @cond - namespace reg_iterator_details - { - constexpr uint32_t iterator_end_offset = 0xffffffff; - constexpr size_t iterator_default_buffer_length = 32; - constexpr size_t iterator_max_keyname_length = 255; - constexpr size_t iterator_max_valuename_length = 16383; + /// @cond + namespace reg_iterator_details + { + constexpr uint32_t iterator_end_offset = 0xffffffff; + constexpr size_t iterator_default_buffer_length = 32; + constexpr size_t iterator_max_keyname_length = 255; + constexpr size_t iterator_max_valuename_length = 16383; - // function overloads to allow *_enumerator objects to be constructed from all 3 types of HKEY representatives - inline HKEY get_hkey(HKEY h) WI_NOEXCEPT - { - return h; - } - inline HKEY get_hkey(const ::wil::unique_hkey& h) WI_NOEXCEPT - { - return h.get(); - } + // function overloads to allow *_enumerator objects to be constructed from all 3 types of HKEY + // representatives + inline HKEY get_hkey(HKEY h) WI_NOEXCEPT + { + return h; + } + inline HKEY get_hkey(const ::wil::unique_hkey &h) WI_NOEXCEPT + { + return h.get(); + } #if defined(__WIL_WINREG_STL) - inline HKEY get_hkey(const ::wil::shared_hkey& h) WI_NOEXCEPT - { - return h.get(); - } + inline HKEY get_hkey(const ::wil::shared_hkey &h) WI_NOEXCEPT + { + return h.get(); + } #endif // #if defined(__WIL_WINREG_STL) #if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) - // overloads for some of the below string functions - specific for std::wstring - // these overloads must be declared before the template functions below, as some of those template functions - // reference these overload functions - inline void clear_name(::std::wstring& name, size_t) WI_NOEXCEPT - { - name.assign(name.size(), L'\0'); - } - inline ::std::wstring copy_name(const ::std::wstring& str, size_t length) WI_NOEXCEPT - { - try + // overloads for some of the below string functions - specific for std::wstring + // these overloads must be declared before the template functions below, as some of those template functions + // reference these overload functions + inline void clear_name(::std::wstring &name, size_t) WI_NOEXCEPT { - // guarantee that the copied string has the specified internal length - // i.e., the same length assumptions hold when the string is copied - ::std::wstring tempString(length, L'0'); - tempString.assign(str); - return tempString; + name.assign(name.size(), L'\0'); } - catch (...) + inline ::std::wstring copy_name(const ::std::wstring &str, size_t length) WI_NOEXCEPT { - return {}; + try + { + // guarantee that the copied string has the specified internal length + // i.e., the same length assumptions hold when the string is copied + ::std::wstring tempString(length, L'0'); + tempString.assign(str); + return tempString; + } + catch (...) + { + return {}; + } + } + inline bool can_derive_length(const ::std::wstring &name) WI_NOEXCEPT + { + return !name.empty(); } - } - inline bool can_derive_length(const ::std::wstring& name) WI_NOEXCEPT - { - return !name.empty(); - } #endif - // string manipulation functions needed for iterator functions - template - PWSTR address_of_name(const T& name) WI_NOEXCEPT - { - return static_cast(::wil::reg::reg_view_details::reg_value_type_info::get_buffer(name)); - } - - template - bool can_derive_length(const T& name) WI_NOEXCEPT - { - return static_cast(address_of_name(name)); - } - - template - bool compare_name(const T& name, PCWSTR comparand) WI_NOEXCEPT - { - if (!can_derive_length(name) || !comparand) + // string manipulation functions needed for iterator functions + template PWSTR address_of_name(const T &name) WI_NOEXCEPT { - return false; + return static_cast(::wil::reg::reg_view_details::reg_value_type_info::get_buffer(name)); } - return 0 == wcscmp(address_of_name(name), comparand); - } - template - void clear_name(const T& name, size_t length) WI_NOEXCEPT - { - if (can_derive_length(name) && length > 0) + template bool can_derive_length(const T &name) WI_NOEXCEPT { - memset(address_of_name(name), 0, length * sizeof(wchar_t)); + return static_cast(address_of_name(name)); } - } - // failure returns zero - template - size_t resize_name_cch(T& name, size_t current_length, size_t new_length) WI_NOEXCEPT - { - if (new_length > current_length) + template bool compare_name(const T &name, PCWSTR comparand) WI_NOEXCEPT { - if (FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( - name, static_cast(new_length * sizeof(wchar_t))))) + if (!can_derive_length(name) || !comparand) { - return 0; + return false; } - current_length = new_length; - // fall through to clear the newly allocated buffer - // and return the new length + return 0 == wcscmp(address_of_name(name), comparand); } - // continue to use the existing buffer since the requested length is less than or equals to the current length - clear_name(name, current_length); - return current_length; - } - - template - T copy_name(const T& name, size_t length) WI_NOEXCEPT - { - if (!can_derive_length(name)) + template void clear_name(const T &name, size_t length) WI_NOEXCEPT { - return {}; + if (can_derive_length(name) && length > 0) + { + memset(address_of_name(name), 0, length * sizeof(wchar_t)); + } + } + + // failure returns zero + template size_t resize_name_cch(T &name, size_t current_length, size_t new_length) WI_NOEXCEPT + { + if (new_length > current_length) + { + if (FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( + name, static_cast(new_length * sizeof(wchar_t))))) + { + return 0; + } + current_length = new_length; + // fall through to clear the newly allocated buffer + // and return the new length + } + + // continue to use the existing buffer since the requested length is less than or equals to the current + // length + clear_name(name, current_length); + return current_length; + } + + template T copy_name(const T &name, size_t length) WI_NOEXCEPT + { + if (!can_derive_length(name)) + { + return {}; + } + return ::wil::make_unique_string_nothrow(address_of_name(name), length); } - return ::wil::make_unique_string_nothrow(address_of_name(name), length); - } #if defined(__WIL_OLEAUTO_H_) - inline ::wil::unique_bstr copy_name(const ::wil::unique_bstr& name, size_t length) WI_NOEXCEPT - { - if (!can_derive_length(name)) + inline ::wil::unique_bstr copy_name(const ::wil::unique_bstr &name, size_t length) WI_NOEXCEPT { - return {}; - } + if (!can_derive_length(name)) + { + return {}; + } - // SysAllocStringLen adds a null, so subtract a wchar_t from the input length - length = length > 0 ? length - 1 : length; - return ::wil::unique_bstr{::SysAllocStringLen(name.get(), static_cast(length))}; - } + // SysAllocStringLen adds a null, so subtract a wchar_t from the input length + length = length > 0 ? length - 1 : length; + return ::wil::unique_bstr{::SysAllocStringLen(name.get(), static_cast(length))}; + } #endif // #if defined(__WIL_OLEAUTO_H_) - } // namespace reg_iterator_details - /// @endcond + } // namespace reg_iterator_details + /// @endcond - // forward declaration to allow friend-ing the template iterator class + // forward declaration to allow friend-ing the template iterator class #if defined(WIL_ENABLE_EXCEPTIONS) - template - class iterator_t; + template class iterator_t; #endif - template - class iterator_nothrow_t; + template class iterator_nothrow_t; - // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) - template - class key_iterator_data - { - public: - T name{}; + // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) + template class key_iterator_data + { + public: + T name{}; - key_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key} - { - } - ~key_iterator_data() WI_NOEXCEPT = default; - - key_iterator_data(const key_iterator_data& rhs) WI_NOEXCEPT - { - // might return null/empty string on failure - name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); - m_hkey = rhs.m_hkey; - m_index = rhs.m_index; - m_name_length = ::wil::reg::reg_iterator_details::can_derive_length(name) ? rhs.m_name_length : 0; - } - key_iterator_data& operator=(const key_iterator_data& rhs) WI_NOEXCEPT - { - if (&rhs != this) + key_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key} { - key_iterator_data temp(rhs); - *this = ::wistd::move(temp); } - return *this; - } + ~key_iterator_data() WI_NOEXCEPT = default; - key_iterator_data(key_iterator_data&& rhs) WI_NOEXCEPT : name{wistd::move(rhs.name)}, - m_hkey{wistd::move(rhs.m_hkey)}, - m_index{wistd::move(rhs.m_index)}, - m_name_length{wistd::move(rhs.m_name_length)} - { - // once name is moved, we must reset m_name_length as name is now empty - rhs.m_name_length = 0; - } - key_iterator_data& operator=(key_iterator_data&& rhs) WI_NOEXCEPT - { - if (&rhs != this) + key_iterator_data(const key_iterator_data &rhs) WI_NOEXCEPT + { + // might return null/empty string on failure + name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); + m_hkey = rhs.m_hkey; + m_index = rhs.m_index; + m_name_length = ::wil::reg::reg_iterator_details::can_derive_length(name) ? rhs.m_name_length : 0; + } + key_iterator_data &operator=(const key_iterator_data &rhs) WI_NOEXCEPT + { + if (&rhs != this) + { + key_iterator_data temp(rhs); + *this = ::wistd::move(temp); + } + return *this; + } + + key_iterator_data(key_iterator_data &&rhs) WI_NOEXCEPT : name{wistd::move(rhs.name)}, + m_hkey{wistd::move(rhs.m_hkey)}, + m_index{wistd::move(rhs.m_index)}, + m_name_length{wistd::move(rhs.m_name_length)} { - name = ::wistd::move(rhs.name); - m_hkey = ::wistd::move(rhs.m_hkey); - m_index = ::wistd::move(rhs.m_index); - m_name_length = ::wistd::move(rhs.m_name_length); // once name is moved, we must reset m_name_length as name is now empty rhs.m_name_length = 0; } - return *this; - } - - // Case-sensitive comparison - bool operator==(PCWSTR comparand) const WI_NOEXCEPT - { - return ::wil::reg::reg_iterator_details::compare_name(name, comparand); - } - - private: -#if defined(WIL_ENABLE_EXCEPTIONS) - friend class ::wil::reg::iterator_t; -#endif - friend class ::wil::reg::iterator_nothrow_t; - - bool at_end() const WI_NOEXCEPT - { - return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - void make_end_iterator() WI_NOEXCEPT - { - ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); - m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - bool resize(size_t new_length) WI_NOEXCEPT - { - // if resize fails, will return 0 - m_name_length = ::wil::reg::reg_iterator_details::resize_name_cch(name, m_name_length, new_length); - return m_name_length > 0; - } - - HRESULT enumerate_current_index() WI_NOEXCEPT - { - FAIL_FAST_IF(at_end()); - - auto string_length = static_cast(m_name_length) > 0 - ? static_cast(m_name_length) - : static_cast(::wil::reg::reg_iterator_details::iterator_default_buffer_length); - for (;;) + key_iterator_data &operator=(key_iterator_data &&rhs) WI_NOEXCEPT { - if (!resize(string_length)) + if (&rhs != this) { - RETURN_HR(E_OUTOFMEMORY); + name = ::wistd::move(rhs.name); + m_hkey = ::wistd::move(rhs.m_hkey); + m_index = ::wistd::move(rhs.m_index); + m_name_length = ::wistd::move(rhs.m_name_length); + // once name is moved, we must reset m_name_length as name is now empty + rhs.m_name_length = 0; } + return *this; + } - const auto error = ::RegEnumKeyExW( - m_hkey, // hKey - m_index, // dwIndex - string_length == 0 ? nullptr : ::wil::reg::reg_iterator_details::address_of_name(name), // lpName - &string_length, // lpcchName - nullptr, // lpReserved - nullptr, // lpClass - nullptr, // lpcchClass - nullptr); // lpftLastWriteTime + // Case-sensitive comparison + bool operator==(PCWSTR comparand) const WI_NOEXCEPT + { + return ::wil::reg::reg_iterator_details::compare_name(name, comparand); + } - if (error == ERROR_SUCCESS) + private: +#if defined(WIL_ENABLE_EXCEPTIONS) + friend class ::wil::reg::iterator_t; +#endif + friend class ::wil::reg::iterator_nothrow_t; + + bool at_end() const WI_NOEXCEPT + { + return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; + } + + void make_end_iterator() WI_NOEXCEPT + { + ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); + m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; + } + + bool resize(size_t new_length) WI_NOEXCEPT + { + // if resize fails, will return 0 + m_name_length = ::wil::reg::reg_iterator_details::resize_name_cch(name, m_name_length, new_length); + return m_name_length > 0; + } + + HRESULT enumerate_current_index() WI_NOEXCEPT + { + FAIL_FAST_IF(at_end()); + + auto string_length = + static_cast(m_name_length) > 0 + ? static_cast(m_name_length) + : static_cast(::wil::reg::reg_iterator_details::iterator_default_buffer_length); + for (;;) { - // string_length returned from RegEnumKeyExW does not include the null terminator - ++string_length; - // if the string type supports resize, we must resize it to the returned string size - // to ensure continuity of the string type with the actual string size - if (::wil::reg::reg_view_details::reg_value_type_info::supports_resize_buffer_bytes()) + if (!resize(string_length)) { - RETURN_IF_FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( - name, string_length * sizeof(WCHAR))); - m_name_length = string_length; + RETURN_HR(E_OUTOFMEMORY); } - if (::wil::reg::reg_view_details::reg_value_type_info::supports_trim_buffer()) + + const auto error = ::RegEnumKeyExW( + m_hkey, // hKey + m_index, // dwIndex + string_length == 0 ? nullptr + : ::wil::reg::reg_iterator_details::address_of_name(name), // lpName + &string_length, // lpcchName + nullptr, // lpReserved + nullptr, // lpClass + nullptr, // lpcchClass + nullptr); // lpftLastWriteTime + + if (error == ERROR_SUCCESS) { - m_name_length = ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); - } - break; - } - if (error == ERROR_NO_MORE_ITEMS) - { - make_end_iterator(); - break; - } - if (error == ERROR_MORE_DATA) - { - // if our default wasn't big enough, resize to either half max or max length and try again - if (string_length < reg_iterator_details::iterator_max_keyname_length / 2) - { - string_length = reg_iterator_details::iterator_max_keyname_length / 2; - } - else if (string_length < reg_iterator_details::iterator_max_keyname_length + 1) - { - string_length = reg_iterator_details::iterator_max_keyname_length + 1; // plus one for null - } - else - { - // if we're already at max length, we can't grow anymore, so we'll just return the error + // string_length returned from RegEnumKeyExW does not include the null terminator + ++string_length; + // if the string type supports resize, we must resize it to the returned string size + // to ensure continuity of the string type with the actual string size + if (::wil::reg::reg_view_details::reg_value_type_info::supports_resize_buffer_bytes()) + { + RETURN_IF_FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( + name, string_length * sizeof(WCHAR))); + m_name_length = string_length; + } + if (::wil::reg::reg_view_details::reg_value_type_info::supports_trim_buffer()) + { + m_name_length = ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); + } break; } - continue; - } - // any other error will fail - RETURN_WIN32(error); - } - return S_OK; - } - - HKEY m_hkey{}; - uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - size_t m_name_length{}; - }; - - // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) - template - class value_iterator_data - { - public: - T name{}; - DWORD type = REG_NONE; - - value_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key} - { - } - ~value_iterator_data() WI_NOEXCEPT = default; - - value_iterator_data(const value_iterator_data& rhs) WI_NOEXCEPT - { - // might return null/empty string on failure - name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); - type = rhs.type; - m_hkey = rhs.m_hkey; - m_index = rhs.m_index; - m_name_length = ::wil::reg::reg_iterator_details::can_derive_length(name) ? rhs.m_name_length : 0; - } - value_iterator_data& operator=(const value_iterator_data& rhs) WI_NOEXCEPT - { - if (&rhs != this) - { - value_iterator_data temp(rhs); - *this = ::wistd::move(temp); - } - return *this; - } - - value_iterator_data(value_iterator_data&&) WI_NOEXCEPT = default; - value_iterator_data& operator=(value_iterator_data&& rhs) WI_NOEXCEPT = default; - - bool at_end() const WI_NOEXCEPT - { - return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - private: -#if defined(WIL_ENABLE_EXCEPTIONS) - friend class ::wil::reg::iterator_t; -#endif - friend class ::wil::reg::iterator_nothrow_t; - - void make_end_iterator() WI_NOEXCEPT - { - ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); - m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - bool resize(size_t new_length) - { - // if resize fails, will return 0 - m_name_length = ::wil::reg::reg_iterator_details::resize_name_cch(name, m_name_length, new_length); - return m_name_length > 0; - } - - HRESULT enumerate_current_index() WI_NOEXCEPT - { - FAIL_FAST_IF(at_end()); - - auto string_length = static_cast(m_name_length) > 0 - ? static_cast(m_name_length) - : static_cast(::wil::reg::reg_iterator_details::iterator_default_buffer_length); - for (;;) - { - if (!resize(string_length)) - { - RETURN_HR(E_OUTOFMEMORY); - } - - const auto error = ::RegEnumValueW( - m_hkey, // hKey - m_index, // dwIndex - string_length == 0 ? nullptr : ::wil::reg::reg_iterator_details::address_of_name(name), // lpValueName - &string_length, // lpcchValueName - nullptr, // lpReserved - &type, // lpType - nullptr, // lpData - nullptr); // lpcbData - - if (error == ERROR_SUCCESS) - { - // string_length returned from RegEnumValueW does not include the null terminator - ++string_length; - // if the string type supports resize, we must resize it to the returned string size - // to ensure continuity of the string type with the actual string size - if (::wil::reg::reg_view_details::reg_value_type_info::supports_resize_buffer_bytes()) + if (error == ERROR_NO_MORE_ITEMS) { - RETURN_IF_FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( - name, string_length * sizeof(WCHAR))); - m_name_length = string_length; - } - if (::wil::reg::reg_view_details::reg_value_type_info::supports_trim_buffer()) - { - m_name_length = ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); - } - break; - } - if (error == ERROR_NO_MORE_ITEMS) - { - make_end_iterator(); - break; - } - if (error == ERROR_MORE_DATA) - { - if (string_length == ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1) - { - // this is the max size, so we can't grow anymore, so we'll just return the error + make_end_iterator(); break; } - - // resize and try again - growing exponentially up to the max - string_length *= 2; - if (string_length > ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1) + if (error == ERROR_MORE_DATA) { - string_length = ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1; + // if our default wasn't big enough, resize to either half max or max length and try again + if (string_length < reg_iterator_details::iterator_max_keyname_length / 2) + { + string_length = reg_iterator_details::iterator_max_keyname_length / 2; + } + else if (string_length < reg_iterator_details::iterator_max_keyname_length + 1) + { + string_length = reg_iterator_details::iterator_max_keyname_length + 1; // plus one for null + } + else + { + // if we're already at max length, we can't grow anymore, so we'll just return the error + break; + } + continue; } - continue; + // any other error will fail + RETURN_WIN32(error); } - - // any other error will fail - RETURN_WIN32(error); + return S_OK; } - return S_OK; - } - HKEY m_hkey{}; - uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - size_t m_name_length{}; - }; + HKEY m_hkey{}; + uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; + size_t m_name_length{}; + }; + + // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) + template class value_iterator_data + { + public: + T name{}; + DWORD type = REG_NONE; + + value_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key} + { + } + ~value_iterator_data() WI_NOEXCEPT = default; + + value_iterator_data(const value_iterator_data &rhs) WI_NOEXCEPT + { + // might return null/empty string on failure + name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); + type = rhs.type; + m_hkey = rhs.m_hkey; + m_index = rhs.m_index; + m_name_length = ::wil::reg::reg_iterator_details::can_derive_length(name) ? rhs.m_name_length : 0; + } + value_iterator_data &operator=(const value_iterator_data &rhs) WI_NOEXCEPT + { + if (&rhs != this) + { + value_iterator_data temp(rhs); + *this = ::wistd::move(temp); + } + return *this; + } + + value_iterator_data(value_iterator_data &&) WI_NOEXCEPT = default; + value_iterator_data &operator=(value_iterator_data &&rhs) WI_NOEXCEPT = default; + + bool at_end() const WI_NOEXCEPT + { + return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; + } + + private: +#if defined(WIL_ENABLE_EXCEPTIONS) + friend class ::wil::reg::iterator_t; +#endif + friend class ::wil::reg::iterator_nothrow_t; + + void make_end_iterator() WI_NOEXCEPT + { + ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); + m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; + } + + bool resize(size_t new_length) + { + // if resize fails, will return 0 + m_name_length = ::wil::reg::reg_iterator_details::resize_name_cch(name, m_name_length, new_length); + return m_name_length > 0; + } + + HRESULT enumerate_current_index() WI_NOEXCEPT + { + FAIL_FAST_IF(at_end()); + + auto string_length = + static_cast(m_name_length) > 0 + ? static_cast(m_name_length) + : static_cast(::wil::reg::reg_iterator_details::iterator_default_buffer_length); + for (;;) + { + if (!resize(string_length)) + { + RETURN_HR(E_OUTOFMEMORY); + } + + const auto error = ::RegEnumValueW( + m_hkey, // hKey + m_index, // dwIndex + string_length == 0 ? nullptr + : ::wil::reg::reg_iterator_details::address_of_name(name), // lpValueName + &string_length, // lpcchValueName + nullptr, // lpReserved + &type, // lpType + nullptr, // lpData + nullptr); // lpcbData + + if (error == ERROR_SUCCESS) + { + // string_length returned from RegEnumValueW does not include the null terminator + ++string_length; + // if the string type supports resize, we must resize it to the returned string size + // to ensure continuity of the string type with the actual string size + if (::wil::reg::reg_view_details::reg_value_type_info::supports_resize_buffer_bytes()) + { + RETURN_IF_FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer_bytes( + name, string_length * sizeof(WCHAR))); + m_name_length = string_length; + } + if (::wil::reg::reg_view_details::reg_value_type_info::supports_trim_buffer()) + { + m_name_length = ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); + } + break; + } + if (error == ERROR_NO_MORE_ITEMS) + { + make_end_iterator(); + break; + } + if (error == ERROR_MORE_DATA) + { + if (string_length == ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1) + { + // this is the max size, so we can't grow anymore, so we'll just return the error + break; + } + + // resize and try again - growing exponentially up to the max + string_length *= 2; + if (string_length > ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1) + { + string_length = ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1; + } + continue; + } + + // any other error will fail + RETURN_WIN32(error); + } + return S_OK; + } + + HKEY m_hkey{}; + uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; + size_t m_name_length{}; + }; #if defined(WIL_ENABLE_EXCEPTIONS) - template - class iterator_t - { - public: - // defining iterator_traits allows STL functions to be used with this iterator class. - // Notice this is a forward_iterator - // - does not support random-access (e.g. vector::iterator) - // - does not support bidirectional access (e.g. list::iterator) + template class iterator_t + { + public: + // defining iterator_traits allows STL functions to be used with this iterator class. + // Notice this is a forward_iterator + // - does not support random-access (e.g. vector::iterator) + // - does not support bidirectional access (e.g. list::iterator) #if WIL_USE_STL || defined(WIL_DOXYGEN) - using iterator_category = ::std::forward_iterator_tag; + using iterator_category = ::std::forward_iterator_tag; #endif - using value_type = T; - using difference_type = size_t; - using distance_type = size_t; - using pointer = T*; - using reference = T&; + using value_type = T; + using difference_type = size_t; + using distance_type = size_t; + using pointer = T *; + using reference = T &; - iterator_t() WI_NOEXCEPT = default; - ~iterator_t() WI_NOEXCEPT = default; + iterator_t() WI_NOEXCEPT = default; + ~iterator_t() WI_NOEXCEPT = default; - iterator_t(HKEY hkey) : m_data(hkey) - { - if (hkey != nullptr) + iterator_t(HKEY hkey) : m_data(hkey) { - m_data.m_index = 0; - THROW_IF_FAILED(m_data.enumerate_current_index()); - } - } - - iterator_t(const iterator_t&) = default; - iterator_t& operator=(const iterator_t&) = default; - iterator_t(iterator_t&&) WI_NOEXCEPT = default; - iterator_t& operator=(iterator_t&&) WI_NOEXCEPT = default; - - // operator support - const T& operator*() const - { - FAIL_FAST_IF(m_data.at_end()); - return m_data; - } - const T& operator*() - { - FAIL_FAST_IF(m_data.at_end()); - return m_data; - } - const T* operator->() const - { - FAIL_FAST_IF(m_data.at_end()); - return &m_data; - } - const T* operator->() - { - FAIL_FAST_IF(m_data.at_end()); - return &m_data; - } - - bool operator==(const iterator_t& rhs) const WI_NOEXCEPT - { - if (m_data.at_end() || rhs.m_data.at_end()) - { - // if either is not initialized (or end), both must not be initialized (or end) to be equal - return m_data.m_index == rhs.m_data.m_index; - } - return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; - } - - bool operator!=(const iterator_t& rhs) const WI_NOEXCEPT - { - return !(*this == rhs); - } - - // pre-increment - iterator_t& operator++() - { - this->operator+=(1); - return *this; - } - const iterator_t& operator++() const - { - this->operator+=(1); - return *this; - } - - // increment by integer - iterator_t& operator+=(size_t offset) - { - uint32_t newIndex = m_data.m_index + static_cast(offset); - if (newIndex < m_data.m_index) - { - // fail on integer overflow - THROW_HR(E_INVALIDARG); - } - if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) - { - // fail if this creates an end iterator - THROW_HR(E_INVALIDARG); + if (hkey != nullptr) + { + m_data.m_index = 0; + THROW_IF_FAILED(m_data.enumerate_current_index()); + } } - // iterate by the integer offset - for (size_t count = 0; count < offset; ++count) + iterator_t(const iterator_t &) = default; + iterator_t &operator=(const iterator_t &) = default; + iterator_t(iterator_t &&) WI_NOEXCEPT = default; + iterator_t &operator=(iterator_t &&) WI_NOEXCEPT = default; + + // operator support + const T &operator*() const { - ++m_data.m_index; - THROW_IF_FAILED(m_data.enumerate_current_index()); + FAIL_FAST_IF(m_data.at_end()); + return m_data; + } + const T &operator*() + { + FAIL_FAST_IF(m_data.at_end()); + return m_data; + } + const T *operator->() const + { + FAIL_FAST_IF(m_data.at_end()); + return &m_data; + } + const T *operator->() + { + FAIL_FAST_IF(m_data.at_end()); + return &m_data; } - return *this; - } - // not supporting post-increment - which would require copy-construction - iterator_t operator++(int) = delete; + bool operator==(const iterator_t &rhs) const WI_NOEXCEPT + { + if (m_data.at_end() || rhs.m_data.at_end()) + { + // if either is not initialized (or end), both must not be initialized (or end) to be equal + return m_data.m_index == rhs.m_data.m_index; + } + return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; + } - private: - // container based on the class template type - T m_data{}; - }; + bool operator!=(const iterator_t &rhs) const WI_NOEXCEPT + { + return !(*this == rhs); + } + + // pre-increment + iterator_t &operator++() + { + this->operator+=(1); + return *this; + } + const iterator_t &operator++() const + { + this->operator+=(1); + return *this; + } + + // increment by integer + iterator_t &operator+=(size_t offset) + { + uint32_t newIndex = m_data.m_index + static_cast(offset); + if (newIndex < m_data.m_index) + { + // fail on integer overflow + THROW_HR(E_INVALIDARG); + } + if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) + { + // fail if this creates an end iterator + THROW_HR(E_INVALIDARG); + } + + // iterate by the integer offset + for (size_t count = 0; count < offset; ++count) + { + ++m_data.m_index; + THROW_IF_FAILED(m_data.enumerate_current_index()); + } + return *this; + } + + // not supporting post-increment - which would require copy-construction + iterator_t operator++(int) = delete; + + private: + // container based on the class template type + T m_data{}; + }; #endif - template - class iterator_nothrow_t - { - public: - iterator_nothrow_t() WI_NOEXCEPT = default; - ~iterator_nothrow_t() WI_NOEXCEPT = default; - - iterator_nothrow_t(HKEY hkey) WI_NOEXCEPT : m_data(hkey) + template class iterator_nothrow_t { - if (hkey != nullptr) - { - m_data.m_index = 0; - m_last_error = m_data.enumerate_current_index(); - } - } + public: + iterator_nothrow_t() WI_NOEXCEPT = default; + ~iterator_nothrow_t() WI_NOEXCEPT = default; - iterator_nothrow_t(const iterator_nothrow_t&) WI_NOEXCEPT = default; - iterator_nothrow_t& operator=(const iterator_nothrow_t&) WI_NOEXCEPT = default; - iterator_nothrow_t(iterator_nothrow_t&&) WI_NOEXCEPT = default; - iterator_nothrow_t& operator=(iterator_nothrow_t&&) WI_NOEXCEPT = default; - - bool at_end() const WI_NOEXCEPT - { - return m_data.at_end(); - } - - HRESULT last_error() const WI_NOEXCEPT - { - return m_last_error; - } - - HRESULT move_next() WI_NOEXCEPT - { - const auto newIndex = m_data.m_index + 1; - if (newIndex < m_data.m_index) + iterator_nothrow_t(HKEY hkey) WI_NOEXCEPT : m_data(hkey) { - // fail on integer overflow - m_last_error = E_INVALIDARG; - } - else if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) - { - // fail if this creates an end iterator - m_last_error = E_INVALIDARG; - } - else - { - m_data.m_index = newIndex; - m_last_error = m_data.enumerate_current_index(); + if (hkey != nullptr) + { + m_data.m_index = 0; + m_last_error = m_data.enumerate_current_index(); + } } - if (FAILED(m_last_error)) + iterator_nothrow_t(const iterator_nothrow_t &) WI_NOEXCEPT = default; + iterator_nothrow_t &operator=(const iterator_nothrow_t &) WI_NOEXCEPT = default; + iterator_nothrow_t(iterator_nothrow_t &&) WI_NOEXCEPT = default; + iterator_nothrow_t &operator=(iterator_nothrow_t &&) WI_NOEXCEPT = default; + + bool at_end() const WI_NOEXCEPT { - // on failure, set the iterator to an end iterator - m_data.make_end_iterator(); + return m_data.at_end(); } - return m_last_error; - } - - // operator support - const T& operator*() const WI_NOEXCEPT - { - return m_data; - } - const T& operator*() WI_NOEXCEPT - { - return m_data; - } - const T* operator->() const WI_NOEXCEPT - { - return &m_data; - } - const T* operator->() WI_NOEXCEPT - { - return &m_data; - } - bool operator==(const iterator_nothrow_t& rhs) const WI_NOEXCEPT - { - if (m_data.at_end() || rhs.m_data.at_end()) + HRESULT last_error() const WI_NOEXCEPT { - // if either is not initialized (or end), both must not be initialized (or end) to be equal - return m_data.m_index == rhs.m_data.m_index; + return m_last_error; } - return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; - } - bool operator!=(const iterator_nothrow_t& rhs) const WI_NOEXCEPT - { - return !(*this == rhs); - } + HRESULT move_next() WI_NOEXCEPT + { + const auto newIndex = m_data.m_index + 1; + if (newIndex < m_data.m_index) + { + // fail on integer overflow + m_last_error = E_INVALIDARG; + } + else if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) + { + // fail if this creates an end iterator + m_last_error = E_INVALIDARG; + } + else + { + m_data.m_index = newIndex; + m_last_error = m_data.enumerate_current_index(); + } - iterator_nothrow_t& operator++() WI_NOEXCEPT - { - move_next(); - return *this; - } - const iterator_nothrow_t& operator++() const WI_NOEXCEPT - { - move_next(); - return *this; - } + if (FAILED(m_last_error)) + { + // on failure, set the iterator to an end iterator + m_data.make_end_iterator(); + } - private: - // container based on the class template type - T m_data{}; - HRESULT m_last_error{}; - }; + return m_last_error; + } -} // namespace reg + // operator support + const T &operator*() const WI_NOEXCEPT + { + return m_data; + } + const T &operator*() WI_NOEXCEPT + { + return m_data; + } + const T *operator->() const WI_NOEXCEPT + { + return &m_data; + } + const T *operator->() WI_NOEXCEPT + { + return &m_data; + } + bool operator==(const iterator_nothrow_t &rhs) const WI_NOEXCEPT + { + if (m_data.at_end() || rhs.m_data.at_end()) + { + // if either is not initialized (or end), both must not be initialized (or end) to be equal + return m_data.m_index == rhs.m_data.m_index; + } + return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; + } + + bool operator!=(const iterator_nothrow_t &rhs) const WI_NOEXCEPT + { + return !(*this == rhs); + } + + iterator_nothrow_t &operator++() WI_NOEXCEPT + { + move_next(); + return *this; + } + const iterator_nothrow_t &operator++() const WI_NOEXCEPT + { + move_next(); + return *this; + } + + private: + // container based on the class template type + T m_data{}; + HRESULT m_last_error{}; + }; + + } // namespace reg } // namespace wil #endif // __WIL_REGISTRY_HELPERS_INCLUDED \ No newline at end of file diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/resource.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/resource.h index 04bba31..660b3d1 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/resource.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/resource.h @@ -9,8 +9,8 @@ // //********************************************************* //! @file -//! WIL Resource Wrappers (RAII): Provides a family of smart pointer patterns and resource wrappers to enable customers to -//! consistently use RAII in all code. +//! WIL Resource Wrappers (RAII): Provides a family of smart pointer patterns and resource wrappers to enable customers +//! to consistently use RAII in all code. #include "result_macros.h" #include "wistd_functional.h" @@ -41,1956 +41,1914 @@ /// @cond namespace Microsoft { -namespace WRL -{ - template - class ComPtr; -} + namespace WRL + { + template class ComPtr; + } } // namespace Microsoft /// @endcond namespace wil { -//! This type copies the current value of GetLastError at construction and resets the last error -//! to that value when it is destroyed. -//! -//! This is useful in library code that runs during a value's destructor. If the library code could -//! inadvertently change the value of GetLastError (by calling a Win32 API or similar), it should -//! instantiate a value of this type before calling the library function in order to preserve the -//! GetLastError value the user would expect. -//! -//! This construct exists to hide kernel mode/user mode differences in wil library code. -//! -//! Example usage: -//! -//! if (!CreateFile(...)) -//! { -//! auto lastError = wil::last_error_context(); -//! WriteFile(g_hlog, logdata); -//! } -//! -class last_error_context -{ + //! This type copies the current value of GetLastError at construction and resets the last error + //! to that value when it is destroyed. + //! + //! This is useful in library code that runs during a value's destructor. If the library code could + //! inadvertently change the value of GetLastError (by calling a Win32 API or similar), it should + //! instantiate a value of this type before calling the library function in order to preserve the + //! GetLastError value the user would expect. + //! + //! This construct exists to hide kernel mode/user mode differences in wil library code. + //! + //! Example usage: + //! + //! if (!CreateFile(...)) + //! { + //! auto lastError = wil::last_error_context(); + //! WriteFile(g_hlog, logdata); + //! } + //! + class last_error_context + { #ifndef WIL_KERNEL_MODE - bool m_dismissed = false; - DWORD m_error = 0; + bool m_dismissed = false; + DWORD m_error = 0; -public: - last_error_context() WI_NOEXCEPT : last_error_context(::GetLastError()) - { - } - - explicit last_error_context(DWORD error) WI_NOEXCEPT : m_error(error) - { - } - - last_error_context(last_error_context&& other) WI_NOEXCEPT - { - operator=(wistd::move(other)); - } - - last_error_context& operator=(last_error_context&& other) WI_NOEXCEPT - { - m_dismissed = wistd::exchange(other.m_dismissed, true); - m_error = other.m_error; - - return *this; - } - - ~last_error_context() WI_NOEXCEPT - { - if (!m_dismissed) + public: + last_error_context() WI_NOEXCEPT : last_error_context(::GetLastError()) { - ::SetLastError(m_error); } - } - //! last_error_context doesn't own a concrete resource, so therefore - //! it just disarms its destructor and returns void. - void release() WI_NOEXCEPT - { - WI_ASSERT(!m_dismissed); - m_dismissed = true; - } + explicit last_error_context(DWORD error) WI_NOEXCEPT : m_error(error) + { + } - WI_NODISCARD auto value() const WI_NOEXCEPT - { - return m_error; - } + last_error_context(last_error_context &&other) WI_NOEXCEPT + { + operator=(wistd::move(other)); + } + + last_error_context &operator=(last_error_context &&other) WI_NOEXCEPT + { + m_dismissed = wistd::exchange(other.m_dismissed, true); + m_error = other.m_error; + + return *this; + } + + ~last_error_context() WI_NOEXCEPT + { + if (!m_dismissed) + { + ::SetLastError(m_error); + } + } + + //! last_error_context doesn't own a concrete resource, so therefore + //! it just disarms its destructor and returns void. + void release() WI_NOEXCEPT + { + WI_ASSERT(!m_dismissed); + m_dismissed = true; + } + + WI_NODISCARD auto value() const WI_NOEXCEPT + { + return m_error; + } #else -public: - void release() WI_NOEXCEPT - { - } + public: + void release() WI_NOEXCEPT + { + } #endif // WIL_KERNEL_MODE -}; - -/// @cond -namespace details -{ - typedef wistd::integral_constant pointer_access_all; // get(), release(), addressof(), and '&' are available - typedef wistd::integral_constant pointer_access_noaddress; // get() and release() are available - typedef wistd::integral_constant pointer_access_none; // the raw pointer is not available - - template - struct close_invoke_helper - { - __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT - { - wistd::invoke(close_fn, value); - } - inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT - { - auto preserveError = last_error_context(); - wistd::invoke(close_fn, value); - } }; - template - struct close_invoke_helper + /// @cond + namespace details { - __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT - { - close_fn(value); - } - inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT - { - auto preserveError = last_error_context(); - close_fn(value); - } - }; + typedef wistd::integral_constant + pointer_access_all; // get(), release(), addressof(), and '&' are available + typedef wistd::integral_constant pointer_access_noaddress; // get() and release() are available + typedef wistd::integral_constant pointer_access_none; // the raw pointer is not available - template - using close_invoker = - close_invoke_helper ? wistd::is_function_v> : false, close_fn_t, close_fn, pointer_storage_t>; + template + struct close_invoke_helper + { + __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT + { + wistd::invoke(close_fn, value); + } + inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT + { + auto preserveError = last_error_context(); + wistd::invoke(close_fn, value); + } + }; - template < - typename pointer_t, // The handle type - typename close_fn_t, // The handle close function type - close_fn_t close_fn, // * and function pointer - typename pointer_access_t = pointer_access_all, // all, noaddress or none to control pointer method access - typename pointer_storage_t = pointer_t, // The type used to store the handle (usually the same as the handle itself) - typename invalid_t = pointer_t, // The invalid handle value type - invalid_t invalid = invalid_t{}, // * and its value (default ZERO value) - typename pointer_invalid_t = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer - struct resource_policy : close_invoker + template + struct close_invoke_helper + { + __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT + { + close_fn(value); + } + inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT + { + auto preserveError = last_error_context(); + close_fn(value); + } + }; + + template + using close_invoker = close_invoke_helper< + wistd::is_pointer_v ? wistd::is_function_v> : false, + close_fn_t, close_fn, pointer_storage_t>; + + template // nullptr_t if the invalid handle value is compatible + // with nullptr, otherwise pointer + struct resource_policy : close_invoker + { + typedef pointer_storage_t pointer_storage; + typedef pointer_t pointer; + typedef pointer_invalid_t pointer_invalid; + typedef pointer_access_t pointer_access; + __forceinline static pointer_storage invalid_value() + { + return (pointer)invalid; + } + __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT + { + return (static_cast(value) != (pointer)invalid); + } + }; + + // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given + // resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug + // into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event + // to be a unique_any formed class, but also expose methods like SetEvent directly. + + template class unique_storage + { + protected: + typedef Policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef unique_storage base_storage; + + public: + unique_storage() WI_NOEXCEPT : m_ptr(policy::invalid_value()) + { + } + + explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : m_ptr(ptr) + { + } + + unique_storage(unique_storage &&other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) + { + other.m_ptr = policy::invalid_value(); + } + + ~unique_storage() WI_NOEXCEPT + { + if (policy::is_valid(m_ptr)) + { + policy::close(m_ptr); + } + } + + WI_NODISCARD bool is_valid() const WI_NOEXCEPT + { + return policy::is_valid(m_ptr); + } + + void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + { + if (policy::is_valid(m_ptr)) + { + policy::close_reset(m_ptr); + } + m_ptr = ptr; + } + + void reset(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, + "reset(nullptr): valid only for handle types using nullptr as the invalid value"); + reset(); + } + + WI_NODISCARD pointer get() const WI_NOEXCEPT + { + return static_cast(m_ptr); + } + + pointer_storage release() WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, + "release(): the raw handle value is not available for this resource class"); + auto ptr = m_ptr; + m_ptr = policy::invalid_value(); + return ptr; + } + + pointer_storage *addressof() WI_NOEXCEPT + { + static_assert(wistd::is_same::value, + "addressof(): the address of the raw handle is not available for this resource class"); + return &m_ptr; + } + + protected: + void replace(unique_storage &&other) WI_NOEXCEPT + { + reset(other.m_ptr); + other.m_ptr = policy::invalid_value(); + } + + private: + pointer_storage m_ptr; + }; + + // Determines if it is safe to deallocate a resource without destructing the object + template struct needs_destruction + { + template + static auto invoke(int) + -> wistd::bool_constant= 0>; // Always true, but SFINAE's if incomplete type + template static auto invoke(float) -> wistd::false_type; + + // A type needs destruction if: + // 1. It is a complete type, + // 2. It can be destructed, and + // 3. It's not trivially destructible + // Note that we need the "complete type" check because some places use an undefined struct as a type-safe + // resource type (e.g. 'typedef struct tagSERIALIZEDPROPSTORAGE SERIALIZEDPROPSTORAGE') + static constexpr const bool value = + wistd::conjunction_v>(0)), + wistd::is_destructible>, + wistd::negation>>>; + }; + + template constexpr bool needs_destruction_v = needs_destruction::value; + + // A pass-through type that statically asserts that the specified type does not need destruction. Useful when + // specifying template arguments for various unique_* types where the destructor won't run + template struct ensure_trivially_destructible + { + // NOTE: Temporary opt-out for existing code that uses these types incorrectly +#ifndef WIL_DISABLE_UNIQUE_PTR_DESTRUCTOR_CHECKS + // If this static_assert fires, it means you've used a type that is not trivially destructible as a template + // argument to a wil::unique* type that will not invoke that object's destructor + static_assert(!needs_destruction_v, "Resource type has a non-trivial destructor, but is used in a " + "context where its destructor will not be run"); +#endif + using type = T; + }; + + template using ensure_trivially_destructible_t = typename ensure_trivially_destructible::type; + } // namespace details + /// @endcond + + // This class when paired with unique_storage and an optional type-specific specialization class implements + // the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class + // supporting attach (reset), detach (release), retrieval (get()). + + template class unique_any_t : public storage_t { - typedef pointer_storage_t pointer_storage; - typedef pointer_t pointer; - typedef pointer_invalid_t pointer_invalid; - typedef pointer_access_t pointer_access; - __forceinline static pointer_storage invalid_value() - { - return (pointer)invalid; - } - __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT - { - return (static_cast(value) != (pointer)invalid); - } - }; - - // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given - // resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug - // into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event - // to be a unique_any formed class, but also expose methods like SetEvent directly. - - template - class unique_storage - { - protected: - typedef Policy policy; + public: + typedef typename storage_t::policy policy; typedef typename policy::pointer_storage pointer_storage; typedef typename policy::pointer pointer; - typedef unique_storage base_storage; - public: - unique_storage() WI_NOEXCEPT : m_ptr(policy::invalid_value()) + unique_any_t(unique_any_t const &) = delete; + unique_any_t &operator=(unique_any_t const &) = delete; + + // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor + // below), but the forwarding constructor causes an internal compiler error when the class is used in a C++ + // array. Defining the default constructor independent of the forwarding constructor removes the compiler + // limitation. + unique_any_t() = default; + + // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class + template + explicit unique_any_t(arg1 &&first, args_t &&...args) + __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) + : storage_t(wistd::forward(first), wistd::forward(args)...) + { + static_assert(wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value, + "pointer_access policy must be a known pointer_access* integral type"); + } + + unique_any_t(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, + "nullptr constructor: valid only for handle types using nullptr as the invalid value"); + } + + unique_any_t(unique_any_t &&other) WI_NOEXCEPT : storage_t(wistd::move(other)) { } - explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : m_ptr(ptr) + unique_any_t &operator=(unique_any_t &&other) WI_NOEXCEPT { - } - - unique_storage(unique_storage&& other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) - { - other.m_ptr = policy::invalid_value(); - } - - ~unique_storage() WI_NOEXCEPT - { - if (policy::is_valid(m_ptr)) + if (this != wistd::addressof(other)) { - policy::close(m_ptr); + // cast to base_storage to 'skip' calling the (optional) specialization class that provides + // handle-specific functionality + storage_t::replace(wistd::move(static_cast(other))); } + return (*this); } - WI_NODISCARD bool is_valid() const WI_NOEXCEPT + unique_any_t &operator=(wistd::nullptr_t) WI_NOEXCEPT { - return policy::is_valid(m_ptr); + static_assert(wistd::is_same::value, + "nullptr assignment: valid only for handle types using nullptr as the invalid value"); + storage_t::reset(); + return (*this); } - void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + void swap(unique_any_t &other) WI_NOEXCEPT { - if (policy::is_valid(m_ptr)) - { - policy::close_reset(m_ptr); - } - m_ptr = ptr; + unique_any_t self(wistd::move(*this)); + operator=(wistd::move(other)); + other = wistd::move(self); } - void reset(wistd::nullptr_t) WI_NOEXCEPT + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT { - static_assert( - wistd::is_same::value, - "reset(nullptr): valid only for handle types using nullptr as the invalid value"); - reset(); + return storage_t::is_valid(); + } + + //! + //! ~~~ + //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle); + //! wil::unique_any waffle; + //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put())); + //! ~~~ + pointer_storage *put() WI_NOEXCEPT + { + static_assert(wistd::is_same::value, + "operator & is not available for this handle"); + storage_t::reset(); + return storage_t::addressof(); + } + + pointer_storage *operator&() WI_NOEXCEPT + { + return put(); } WI_NODISCARD pointer get() const WI_NOEXCEPT { - return static_cast(m_ptr); + static_assert(!wistd::is_same::value, + "get(): the raw handle value is not available for this resource class"); + return storage_t::get(); } - pointer_storage release() WI_NOEXCEPT + // The following functions are publicly exposed by their inclusion in the unique_storage base class + + // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT + // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + // void reset(wistd::nullptr_t) WI_NOEXCEPT + // pointer_storage release() WI_NOEXCEPT // not exposed for some resource + // types pointer_storage *addressof() WI_NOEXCEPT // not exposed for some + // resource types + }; + + template void swap(unique_any_t &left, unique_any_t &right) WI_NOEXCEPT + { + left.swap(right); + } + + template + bool operator==(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (left.get() == right.get()); + } + + template bool operator==(const unique_any_t &left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !left; + } + + template bool operator==(wistd::nullptr_t, const unique_any_t &right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !right; + } + + template + bool operator!=(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (!(left.get() == right.get())); + } + + template bool operator!=(const unique_any_t &left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !!left; + } + + template bool operator!=(wistd::nullptr_t, const unique_any_t &right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !!right; + } + + template + bool operator<(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (left.get() < right.get()); + } + + template + bool operator>=(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (!(left < right)); + } + + template + bool operator>(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (right < left); + } + + template + bool operator<=(const unique_any_t &left, const unique_any_t &right) WI_NOEXCEPT + { + return (!(right < left)); + } + + // unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the + // given template parameters for resource_policy. + + template < + typename pointer, // The handle type + typename close_fn_t, // The handle close function type + close_fn_t close_fn, // * and function pointer + typename pointer_access = + details::pointer_access_all, // all, noaddress or none to control pointer method access + typename pointer_storage = pointer, // The type used to store the handle (usually the same as the handle itself) + typename invalid_t = pointer, // The invalid handle value type + invalid_t invalid = invalid_t{}, // * and its value (default ZERO value) + typename pointer_invalid = + wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer + using unique_any = unique_any_t>>; + + /// @cond + namespace details + { + template class lambda_call + { + public: + lambda_call(const lambda_call &) = delete; + lambda_call &operator=(const lambda_call &) = delete; + lambda_call &operator=(lambda_call &&other) = delete; + + explicit lambda_call(TLambda &&lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda)) + { + static_assert(wistd::is_same::value, + "scope_exit lambdas must not have a return value"); + static_assert(!wistd::is_lvalue_reference::value && + !wistd::is_rvalue_reference::value, + "scope_exit should only be directly used with a lambda"); + } + + lambda_call(lambda_call &&other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) + { + other.m_call = false; + } + + ~lambda_call() WI_NOEXCEPT + { + reset(); + } + + // Ensures the scope_exit lambda will not be called + void release() WI_NOEXCEPT + { + m_call = false; + } + + // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again + void reset() WI_NOEXCEPT + { + if (m_call) + { + m_call = false; + m_lambda(); + } + } + + // Returns true if the scope_exit lambda is still going to be executed + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + protected: + TLambda m_lambda; + bool m_call = true; + }; + +#ifdef WIL_ENABLE_EXCEPTIONS + template class lambda_call_log + { + public: + lambda_call_log(const lambda_call_log &) = delete; + lambda_call_log &operator=(const lambda_call_log &) = delete; + lambda_call_log &operator=(lambda_call_log &&other) = delete; + + explicit lambda_call_log(void *address, const DiagnosticsInfo &info, TLambda &&lambda) WI_NOEXCEPT + : m_address(address), + m_info(info), + m_lambda(wistd::move(lambda)) + { + static_assert(wistd::is_same::value, "scope_exit lambdas must return 'void'"); + static_assert(!wistd::is_lvalue_reference::value && + !wistd::is_rvalue_reference::value, + "scope_exit should only be directly used with a lambda"); + } + + lambda_call_log(lambda_call_log &&other) WI_NOEXCEPT : m_address(other.m_address), + m_info(other.m_info), + m_lambda(wistd::move(other.m_lambda)), + m_call(other.m_call) + { + other.m_call = false; + } + + ~lambda_call_log() WI_NOEXCEPT + { + reset(); + } + + // Ensures the scope_exit lambda will not be called + void release() WI_NOEXCEPT + { + m_call = false; + } + + // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again + void reset() WI_NOEXCEPT + { + if (m_call) + { + m_call = false; + try + { + m_lambda(); + } + catch (...) + { + ReportFailure_CaughtException(__R_DIAGNOSTICS(m_info), m_address); + } + } + } + + // Returns true if the scope_exit lambda is still going to be executed + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + private: + void *m_address; + DiagnosticsInfo m_info; + TLambda m_lambda; + bool m_call = true; + }; +#endif // WIL_ENABLE_EXCEPTIONS + } // namespace details + /// @endcond + + /** Returns an object that executes the given lambda when destroyed. + Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid + execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */ + template WI_NODISCARD inline auto scope_exit(TLambda &&lambda) WI_NOEXCEPT + { + return details::lambda_call(wistd::forward(lambda)); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Returns an object that executes the given lambda when destroyed; logs exceptions. + Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid + execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */ + template + WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo &diagnostics, + TLambda &&lambda) WI_NOEXCEPT + { + return details::lambda_call_log(_ReturnAddress(), diagnostics, wistd::forward(lambda)); + } +#endif + + // Forward declaration... + template class com_ptr_t; + + //! Type traits class that identifies the inner type of any smart pointer. + template struct smart_pointer_details + { + typedef typename Ptr::pointer pointer; + }; + + /// @cond + template struct smart_pointer_details> + { + typedef T *pointer; + }; + /// @endcond + + /** Generically detaches a raw pointer from any smart pointer. + Caller takes ownership of the returned raw pointer; calls the correct release(), detach(), + or Detach() method based on the smart pointer type */ + template + WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer &smartPtr) + { + return smartPtr.release(); + } + + /// @cond + // Generically detaches a raw pointer from any smart pointer + template WI_NODISCARD T *detach_from_smart_pointer(wil::com_ptr_t &smartPtr) + { + return smartPtr.detach(); + } + + // Generically detaches a raw pointer from any smart pointer + template WI_NODISCARD T *detach_from_smart_pointer(Microsoft::WRL::ComPtr &smartPtr) + { + return smartPtr.Detach(); + } + + template class com_ptr_t; // forward + namespace details + { + // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t. + // To solve that use this functions return type to eliminate the reset form for com_ptr_t. + template wistd::false_type use_reset(wil::com_ptr_t *) + { + return wistd::false_type(); + } + template wistd::true_type use_reset(T *) + { + return wistd::true_type(); + } + } // namespace details + /// @endcond + + /** Generically attach a raw pointer to a compatible smart pointer. + Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */ + template (nullptr)))::value>> + void attach_to_smart_pointer(TSmartPointer &smartPtr, typename TSmartPointer::pointer rawPtr) + { + smartPtr.reset(rawPtr); + } + + /// @cond + + // Generically attach a raw pointer to a compatible smart pointer. + template void attach_to_smart_pointer(wil::com_ptr_t &smartPtr, T *rawPtr) + { + smartPtr.attach(rawPtr); + } + + // Generically attach a raw pointer to a compatible smart pointer. + template void attach_to_smart_pointer(Microsoft::WRL::ComPtr &smartPtr, T *rawPtr) + { + smartPtr.Attach(rawPtr); + } + /// @endcond + + //! @ingroup outparam + /** Detach a smart pointer resource to an optional output pointer parameter. + Avoids cluttering code with nullptr tests; works generically for any smart pointer */ + template + inline void detach_to_opt_param(_Out_opt_ T *outParam, TSmartPointer &&smartPtr) + { + if (outParam) + { + *outParam = detach_from_smart_pointer(smartPtr); + } + } + + /// @cond + namespace details + { + template struct out_param_t + { + typedef typename wil::smart_pointer_details::pointer pointer; + T &wrapper; + pointer pRaw; + bool replace = true; + + out_param_t(_Inout_ T &output) : wrapper(output), pRaw(nullptr) + { + } + + out_param_t(out_param_t &&other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw) + { + WI_ASSERT(other.replace); + other.replace = false; + } + + operator pointer *() + { + WI_ASSERT(replace); + return &pRaw; + } + + ~out_param_t() + { + if (replace) + { + attach_to_smart_pointer(wrapper, pRaw); + } + } + + out_param_t(out_param_t const &other) = delete; + out_param_t &operator=(out_param_t const &other) = delete; + }; + + template struct out_param_ptr_t + { + typedef typename wil::smart_pointer_details::pointer pointer; + T &wrapper; + pointer pRaw; + bool replace = true; + + out_param_ptr_t(_Inout_ T &output) : wrapper(output), pRaw(nullptr) + { + } + + out_param_ptr_t(out_param_ptr_t &&other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw) + { + WI_ASSERT(other.replace); + other.replace = false; + } + + operator Tcast() + { + WI_ASSERT(replace); + return reinterpret_cast(&pRaw); + } + + ~out_param_ptr_t() + { + if (replace) + { + attach_to_smart_pointer(wrapper, pRaw); + } + } + + out_param_ptr_t(out_param_ptr_t const &other) = delete; + out_param_ptr_t &operator=(out_param_ptr_t const &other) = delete; + }; + } // namespace details + /// @endcond + + /** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator. + This avoids multi-step handling of a raw resource to establish the smart pointer. + Example: `GetFoo(out_param(foo));` */ + template details::out_param_t out_param(T &p) + { + return details::out_param_t(p); + } + + /** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the + '&' operator. Use only when the smart pointer's &handle is not equal to the output type a function requires, + necessitating a cast. Example: `wil::out_param_ptr(securityDescriptor)` */ + template details::out_param_ptr_t out_param_ptr(T &p) + { + return details::out_param_ptr_t(p); + } + + /** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up. + Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. + If no custom initialier function is defined in the template then ZeroMemory is used. Unique_struct is modeled off of + std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the struct through a + private member variable. + + If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). + Submit pull requests to [GitHub](https://github.com/microsoft/wil/). Otherwise, if the type is local to your + project, declare it locally. + @tparam struct_t The struct you want to manage + @tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. + Return values are ignored. + @tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions. + @tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of + struct_t. Return values are ignored. + @tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release + functions. The default is ZeroMemory to initialize the struct. + + Defined using the default zero memory initializer + ~~~ + typedef wil::unique_struct + unique_prop_variant_default_init; + + unique_prop_variant_default_init propvariant; + SomeFunction(&propvariant); + ~~~ + + Defined using a custom initializer + ~~~ + typedef wil::unique_struct unique_prop_variant; + + unique_prop_variant propvariant; + SomeFunction(&propvariant); + ~~~ + */ + template + class unique_struct : public struct_t + { + using closer = details::close_invoker; + + public: + //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function + //! is specified + unique_struct() + { + call_init(use_default_init_fn()); + } + + //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t + explicit unique_struct(const struct_t &other) WI_NOEXCEPT : struct_t(other) + { + } + + //! Initializes the managed struct by taking the ownership of the other managed struct + //! Then resets the other managed struct by calling the custom close function + unique_struct(unique_struct &&other) WI_NOEXCEPT : struct_t(other.release()) + { + } + + //! Resets this managed struct by calling the custom close function and takes ownership of the other managed + //! struct Then resets the other managed struct by calling the custom close function + unique_struct &operator=(unique_struct &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(other.release()); + } + return *this; + } + + //! Calls the custom close function + ~unique_struct() WI_NOEXCEPT + { + closer::close(this); + } + + void reset(const unique_struct &) = delete; + + //! Resets this managed struct by calling the custom close function and begins management of the other struct + void reset(const struct_t &other) WI_NOEXCEPT + { + closer::close_reset(this); + struct_t::operator=(other); + } + + //! Resets this managed struct by calling the custom close function + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no + //! function is specified + void reset() WI_NOEXCEPT + { + closer::close(this); + call_init(use_default_init_fn()); + } + + void swap(struct_t &) = delete; + + //! Swaps the managed structs + void swap(unique_struct &other) WI_NOEXCEPT + { + struct_t self(*this); + struct_t::operator=(other); + *(other.addressof()) = self; + } + + //! Returns the managed struct + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no + //! function is specified + struct_t release() WI_NOEXCEPT + { + struct_t value(*this); + call_init(use_default_init_fn()); + return value; + } + + //! Returns address of the managed struct + struct_t *addressof() WI_NOEXCEPT + { + return this; + } + + //! Resets this managed struct by calling the custom close function + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no + //! function is specified. Returns address of the managed struct + struct_t *reset_and_addressof() WI_NOEXCEPT + { + reset(); + return this; + } + + unique_struct(const unique_struct &) = delete; + unique_struct &operator=(const unique_struct &) = delete; + unique_struct &operator=(const struct_t &) = delete; + + private: + typedef typename wistd::is_same::type use_default_init_fn; + + void call_init(wistd::true_type) + { + // Suppress '-Wnontrivial-memcall' with 'static_cast' + RtlZeroMemory(static_cast(this), sizeof(*this)); + } + + void call_init(wistd::false_type) + { + init_fn(this); + } + }; + + struct empty_deleter + { + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const + { + static_assert(!details::needs_destruction_v, "Resource type has a non-trivial destructor, but is used " + "in a context where its destructor will not be run"); + } + }; + + /** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that + may need to be freed. The intended use for this RAII type would be to capture out params from API like + IPropertyValue::GetStringArray. This class also maintains the size of the array, so it can iterate over the members + and deallocate them before it deallocates the base array pointer. + + If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send + pull requests to [GitHub](https://github.com/microsoft/wil/). Otherwise, if the type is local to your project, + declare it locally. + + @tparam ValueType: The type of array you want to manage. + @tparam ArrayDeleter: The type of the function to clean up the array. Takes one parameter of type T[] or T*. Return + values are ignored. This is called in the destructor and reset functions. + @tparam ElementDeleter: The type of the function to clean up the array elements. Takes one parameter of type T. + Return values are ignored. This is called in the destructor and reset functions. + + ~~~ + void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**); + + struct not_my_deleter + { + void operator()(NOTMYTYPE p) const + { + destroy(p); + } + }; + + wil::unique_any_array_ptr myArray; + GetSomeArray(myArray.size_address(), &myArray); + ~~~ */ + template + class unique_any_array_ptr + { + public: + typedef ValueType value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef ValueType *pointer; + typedef const ValueType *const_pointer; + typedef ValueType &reference; + typedef const ValueType &const_reference; + + typedef ValueType *iterator; + typedef const ValueType *const_iterator; + + unique_any_array_ptr() = default; + unique_any_array_ptr(const unique_any_array_ptr &) = delete; + unique_any_array_ptr &operator=(const unique_any_array_ptr &) = delete; + + unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT + { + } + + unique_any_array_ptr &operator=(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + return *this; + } + + unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size) + { + } + + unique_any_array_ptr(unique_any_array_ptr &&other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size) + { + other.m_ptr = nullptr; + other.m_size = size_type{}; + } + + unique_any_array_ptr &operator=(unique_any_array_ptr &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + swap(other); + } + return *this; + } + + ~unique_any_array_ptr() WI_NOEXCEPT + { + reset(); + } + + void swap(unique_any_array_ptr &other) WI_NOEXCEPT { - static_assert( - !wistd::is_same::value, - "release(): the raw handle value is not available for this resource class"); auto ptr = m_ptr; - m_ptr = policy::invalid_value(); - return ptr; + auto size = m_size; + m_ptr = other.m_ptr; + m_size = other.m_size; + other.m_ptr = ptr; + other.m_size = size; } - pointer_storage* addressof() WI_NOEXCEPT + WI_NODISCARD iterator begin() WI_NOEXCEPT + { + return (iterator(m_ptr)); + } + + WI_NODISCARD const_iterator begin() const WI_NOEXCEPT + { + return (const_iterator(m_ptr)); + } + + WI_NODISCARD iterator end() WI_NOEXCEPT + { + return (iterator(m_ptr + m_size)); + } + + WI_NODISCARD const_iterator end() const WI_NOEXCEPT + { + return (const_iterator(m_ptr + m_size)); + } + + WI_NODISCARD const_iterator cbegin() const WI_NOEXCEPT + { + return (begin()); + } + + WI_NODISCARD const_iterator cend() const WI_NOEXCEPT + { + return (end()); + } + + WI_NODISCARD size_type size() const WI_NOEXCEPT + { + return (m_size); + } + + WI_NODISCARD bool empty() const WI_NOEXCEPT + { + return (size() == size_type{}); + } + + WI_NODISCARD reference operator[](size_type position) + { + WI_ASSERT(position < m_size); + _Analysis_assume_(position < m_size); + return (m_ptr[position]); + } + + WI_NODISCARD const_reference operator[](size_type position) const + { + WI_ASSERT(position < m_size); + _Analysis_assume_(position < m_size); + return (m_ptr[position]); + } + + WI_NODISCARD reference front() + { + WI_ASSERT(!empty()); + return (m_ptr[0]); + } + + WI_NODISCARD const_reference front() const + { + WI_ASSERT(!empty()); + return (m_ptr[0]); + } + + WI_NODISCARD reference back() + { + WI_ASSERT(!empty()); + return (m_ptr[m_size - 1]); + } + + WI_NODISCARD const_reference back() const + { + WI_ASSERT(!empty()); + return (m_ptr[m_size - 1]); + } + + WI_NODISCARD ValueType *data() WI_NOEXCEPT + { + return (m_ptr); + } + + WI_NODISCARD const ValueType *data() const WI_NOEXCEPT + { + return (m_ptr); + } + + WI_NODISCARD pointer get() const WI_NOEXCEPT + { + return m_ptr; + } + + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != pointer()); + } + + pointer release() WI_NOEXCEPT + { + auto result = m_ptr; + m_ptr = nullptr; + m_size = size_type{}; + return result; + } + + void reset() WI_NOEXCEPT + { + if (m_ptr) + { + reset_array(ElementDeleter()); + ArrayDeleter()(m_ptr); + m_ptr = nullptr; + m_size = size_type{}; + } + } + + void reset(pointer ptr, size_t size) WI_NOEXCEPT + { + reset(); + m_ptr = ptr; + m_size = size; + } + + pointer *addressof() WI_NOEXCEPT { - static_assert( - wistd::is_same::value, - "addressof(): the address of the raw handle is not available for this resource class"); return &m_ptr; } - protected: - void replace(unique_storage&& other) WI_NOEXCEPT - { - reset(other.m_ptr); - other.m_ptr = policy::invalid_value(); - } - - private: - pointer_storage m_ptr; - }; - - // Determines if it is safe to deallocate a resource without destructing the object - template - struct needs_destruction - { - template - static auto invoke(int) -> wistd::bool_constant= 0>; // Always true, but SFINAE's if incomplete type - template - static auto invoke(float) -> wistd::false_type; - - // A type needs destruction if: - // 1. It is a complete type, - // 2. It can be destructed, and - // 3. It's not trivially destructible - // Note that we need the "complete type" check because some places use an undefined struct as a type-safe - // resource type (e.g. 'typedef struct tagSERIALIZEDPROPSTORAGE SERIALIZEDPROPSTORAGE') - static constexpr const bool value = wistd::conjunction_v< - decltype(invoke>(0)), - wistd::is_destructible>, - wistd::negation>>>; - }; - - template - constexpr bool needs_destruction_v = needs_destruction::value; - - // A pass-through type that statically asserts that the specified type does not need destruction. Useful when - // specifying template arguments for various unique_* types where the destructor won't run - template - struct ensure_trivially_destructible - { - // NOTE: Temporary opt-out for existing code that uses these types incorrectly -#ifndef WIL_DISABLE_UNIQUE_PTR_DESTRUCTOR_CHECKS - // If this static_assert fires, it means you've used a type that is not trivially destructible as a template - // argument to a wil::unique* type that will not invoke that object's destructor - static_assert(!needs_destruction_v, "Resource type has a non-trivial destructor, but is used in a context where its destructor will not be run"); -#endif - using type = T; - }; - - template - using ensure_trivially_destructible_t = typename ensure_trivially_destructible::type; -} // namespace details -/// @endcond - -// This class when paired with unique_storage and an optional type-specific specialization class implements -// the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class -// supporting attach (reset), detach (release), retrieval (get()). - -template -class unique_any_t : public storage_t -{ -public: - typedef typename storage_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - - unique_any_t(unique_any_t const&) = delete; - unique_any_t& operator=(unique_any_t const&) = delete; - - // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but - // the forwarding constructor causes an internal compiler error when the class is used in a C++ array. Defining the default - // constructor independent of the forwarding constructor removes the compiler limitation. - unique_any_t() = default; - - // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class - template - explicit unique_any_t(arg1&& first, args_t&&... args) - __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) : - storage_t(wistd::forward(first), wistd::forward(args)...) - { - static_assert( - wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value, - "pointer_access policy must be a known pointer_access* integral type"); - } - - unique_any_t(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert( - wistd::is_same::value, - "nullptr constructor: valid only for handle types using nullptr as the invalid value"); - } - - unique_any_t(unique_any_t&& other) WI_NOEXCEPT : storage_t(wistd::move(other)) - { - } - - unique_any_t& operator=(unique_any_t&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - // cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality - storage_t::replace(wistd::move(static_cast(other))); - } - return (*this); - } - - unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert( - wistd::is_same::value, - "nullptr assignment: valid only for handle types using nullptr as the invalid value"); - storage_t::reset(); - return (*this); - } - - void swap(unique_any_t& other) WI_NOEXCEPT - { - unique_any_t self(wistd::move(*this)); - operator=(wistd::move(other)); - other = wistd::move(self); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return storage_t::is_valid(); - } - - //! - //! ~~~ - //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle); - //! wil::unique_any waffle; - //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put())); - //! ~~~ - pointer_storage* put() WI_NOEXCEPT - { - static_assert( - wistd::is_same::value, - "operator & is not available for this handle"); - storage_t::reset(); - return storage_t::addressof(); - } - - pointer_storage* operator&() WI_NOEXCEPT - { - return put(); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - static_assert( - !wistd::is_same::value, - "get(): the raw handle value is not available for this resource class"); - return storage_t::get(); - } - - // The following functions are publicly exposed by their inclusion in the unique_storage base class - - // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT - // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT - // void reset(wistd::nullptr_t) WI_NOEXCEPT - // pointer_storage release() WI_NOEXCEPT // not exposed for some resource types - // pointer_storage *addressof() WI_NOEXCEPT // not exposed for some resource types -}; - -template -void swap(unique_any_t& left, unique_any_t& right) WI_NOEXCEPT -{ - left.swap(right); -} - -template -bool operator==(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (left.get() == right.get()); -} - -template -bool operator==(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !left; -} - -template -bool operator==(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !right; -} - -template -bool operator!=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (!(left.get() == right.get())); -} - -template -bool operator!=(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !!left; -} - -template -bool operator!=(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !!right; -} - -template -bool operator<(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (left.get() < right.get()); -} - -template -bool operator>=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (!(left < right)); -} - -template -bool operator>(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (right < left); -} - -template -bool operator<=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT -{ - return (!(right < left)); -} - -// unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given -// template parameters for resource_policy. - -template < - typename pointer, // The handle type - typename close_fn_t, // The handle close function type - close_fn_t close_fn, // * and function pointer - typename pointer_access = details::pointer_access_all, // all, noaddress or none to control pointer method access - typename pointer_storage = pointer, // The type used to store the handle (usually the same as the handle itself) - typename invalid_t = pointer, // The invalid handle value type - invalid_t invalid = invalid_t{}, // * and its value (default ZERO value) - typename pointer_invalid = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer -using unique_any = - unique_any_t>>; - -/// @cond -namespace details -{ - template - class lambda_call - { - public: - lambda_call(const lambda_call&) = delete; - lambda_call& operator=(const lambda_call&) = delete; - lambda_call& operator=(lambda_call&& other) = delete; - - explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda)) - { - static_assert(wistd::is_same::value, "scope_exit lambdas must not have a return value"); - static_assert( - !wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, - "scope_exit should only be directly used with a lambda"); - } - - lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) - { - other.m_call = false; - } - - ~lambda_call() WI_NOEXCEPT + pointer *put() WI_NOEXCEPT { reset(); + return addressof(); } - // Ensures the scope_exit lambda will not be called - void release() WI_NOEXCEPT + pointer *operator&() WI_NOEXCEPT { - m_call = false; + return put(); } - // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again - void reset() WI_NOEXCEPT + size_type *size_address() WI_NOEXCEPT { - if (m_call) + return &m_size; + } + + template struct size_address_ptr + { + unique_any_array_ptr &wrapper; + TSize size{}; + bool replace = true; + + size_address_ptr(_Inout_ unique_any_array_ptr &output) : wrapper(output) { - m_call = false; - m_lambda(); } - } - // Returns true if the scope_exit lambda is still going to be executed - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_call; - } - - protected: - TLambda m_lambda; - bool m_call = true; - }; - -#ifdef WIL_ENABLE_EXCEPTIONS - template - class lambda_call_log - { - public: - lambda_call_log(const lambda_call_log&) = delete; - lambda_call_log& operator=(const lambda_call_log&) = delete; - lambda_call_log& operator=(lambda_call_log&& other) = delete; - - explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT - : m_address(address), - m_info(info), - m_lambda(wistd::move(lambda)) - { - static_assert(wistd::is_same::value, "scope_exit lambdas must return 'void'"); - static_assert( - !wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, - "scope_exit should only be directly used with a lambda"); - } - - lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT : m_address(other.m_address), - m_info(other.m_info), - m_lambda(wistd::move(other.m_lambda)), - m_call(other.m_call) - { - other.m_call = false; - } - - ~lambda_call_log() WI_NOEXCEPT - { - reset(); - } - - // Ensures the scope_exit lambda will not be called - void release() WI_NOEXCEPT - { - m_call = false; - } - - // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again - void reset() WI_NOEXCEPT - { - if (m_call) + size_address_ptr(size_address_ptr &&other) WI_NOEXCEPT : wrapper(other.wrapper), size(other.size) { - m_call = false; - try + WI_ASSERT(other.replace); + other.replace = false; + } + + operator TSize *() + { + WI_ASSERT(replace); + return &size; + } + + ~size_address_ptr() + { + if (replace) { - m_lambda(); - } - catch (...) - { - ReportFailure_CaughtException(__R_DIAGNOSTICS(m_info), m_address); + *wrapper.size_address() = static_cast(size); } } - } - // Returns true if the scope_exit lambda is still going to be executed - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + size_address_ptr(size_address_ptr const &other) = delete; + size_address_ptr &operator=(size_address_ptr const &other) = delete; + }; + + template size_address_ptr size_address() WI_NOEXCEPT { - return m_call; + return size_address_ptr(*this); } - private: - void* m_address; - DiagnosticsInfo m_info; - TLambda m_lambda; - bool m_call = true; - }; -#endif // WIL_ENABLE_EXCEPTIONS -} // namespace details -/// @endcond + private: + pointer m_ptr = nullptr; + size_type m_size{}; -/** Returns an object that executes the given lambda when destroyed. -Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid -execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */ -template -WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT -{ - return details::lambda_call(wistd::forward(lambda)); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -/** Returns an object that executes the given lambda when destroyed; logs exceptions. -Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid -execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */ -template -WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT -{ - return details::lambda_call_log(_ReturnAddress(), diagnostics, wistd::forward(lambda)); -} -#endif - -// Forward declaration... -template -class com_ptr_t; - -//! Type traits class that identifies the inner type of any smart pointer. -template -struct smart_pointer_details -{ - typedef typename Ptr::pointer pointer; -}; - -/// @cond -template -struct smart_pointer_details> -{ - typedef T* pointer; -}; -/// @endcond - -/** Generically detaches a raw pointer from any smart pointer. -Caller takes ownership of the returned raw pointer; calls the correct release(), detach(), -or Detach() method based on the smart pointer type */ -template -WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr) -{ - return smartPtr.release(); -} - -/// @cond -// Generically detaches a raw pointer from any smart pointer -template -WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t& smartPtr) -{ - return smartPtr.detach(); -} - -// Generically detaches a raw pointer from any smart pointer -template -WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr& smartPtr) -{ - return smartPtr.Detach(); -} - -template -class com_ptr_t; // forward -namespace details -{ - // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t. - // To solve that use this functions return type to eliminate the reset form for com_ptr_t. - template - wistd::false_type use_reset(wil::com_ptr_t*) - { - return wistd::false_type(); - } - template - wistd::true_type use_reset(T*) - { - return wistd::true_type(); - } -} // namespace details -/// @endcond - -/** Generically attach a raw pointer to a compatible smart pointer. -Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */ -template (nullptr)))::value>> -void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr) -{ - smartPtr.reset(rawPtr); -} - -/// @cond - -// Generically attach a raw pointer to a compatible smart pointer. -template -void attach_to_smart_pointer(wil::com_ptr_t& smartPtr, T* rawPtr) -{ - smartPtr.attach(rawPtr); -} - -// Generically attach a raw pointer to a compatible smart pointer. -template -void attach_to_smart_pointer(Microsoft::WRL::ComPtr& smartPtr, T* rawPtr) -{ - smartPtr.Attach(rawPtr); -} -/// @endcond - -//! @ingroup outparam -/** Detach a smart pointer resource to an optional output pointer parameter. -Avoids cluttering code with nullptr tests; works generically for any smart pointer */ -template -inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr) -{ - if (outParam) - { - *outParam = detach_from_smart_pointer(smartPtr); - } -} - -/// @cond -namespace details -{ - template - struct out_param_t - { - typedef typename wil::smart_pointer_details::pointer pointer; - T& wrapper; - pointer pRaw; - bool replace = true; - - out_param_t(_Inout_ T& output) : wrapper(output), pRaw(nullptr) + void reset_array(const empty_deleter &) { } - out_param_t(out_param_t&& other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw) + template void reset_array(const T &deleter) { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator pointer*() - { - WI_ASSERT(replace); - return &pRaw; - } - - ~out_param_t() - { - if (replace) + for (auto &element : make_range(m_ptr, m_size)) { - attach_to_smart_pointer(wrapper, pRaw); - } - } - - out_param_t(out_param_t const& other) = delete; - out_param_t& operator=(out_param_t const& other) = delete; - }; - - template - struct out_param_ptr_t - { - typedef typename wil::smart_pointer_details::pointer pointer; - T& wrapper; - pointer pRaw; - bool replace = true; - - out_param_ptr_t(_Inout_ T& output) : wrapper(output), pRaw(nullptr) - { - } - - out_param_ptr_t(out_param_ptr_t&& other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw) - { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator Tcast() - { - WI_ASSERT(replace); - return reinterpret_cast(&pRaw); - } - - ~out_param_ptr_t() - { - if (replace) - { - attach_to_smart_pointer(wrapper, pRaw); - } - } - - out_param_ptr_t(out_param_ptr_t const& other) = delete; - out_param_ptr_t& operator=(out_param_ptr_t const& other) = delete; - }; -} // namespace details -/// @endcond - -/** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator. -This avoids multi-step handling of a raw resource to establish the smart pointer. -Example: `GetFoo(out_param(foo));` */ -template -details::out_param_t out_param(T& p) -{ - return details::out_param_t(p); -} - -/** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator. -Use only when the smart pointer's &handle is not equal to the output type a function requires, necessitating a cast. -Example: `wil::out_param_ptr(securityDescriptor)` */ -template -details::out_param_ptr_t out_param_ptr(T& p) -{ - return details::out_param_ptr_t(p); -} - -/** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up. -Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. If no custom -initialier function is defined in the template then ZeroMemory is used. -Unique_struct is modeled off of std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the -struct through a private member variable. - -If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Submit pull -requests to [GitHub](https://github.com/microsoft/wil/). Otherwise, if the type is local to your project, declare it locally. -@tparam struct_t The struct you want to manage -@tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. Return values are - ignored. -@tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions. -@tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of struct_t. Return - values are ignored. -@tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release functions. The - default is ZeroMemory to initialize the struct. - -Defined using the default zero memory initializer -~~~ -typedef wil::unique_struct unique_prop_variant_default_init; - -unique_prop_variant_default_init propvariant; -SomeFunction(&propvariant); -~~~ - -Defined using a custom initializer -~~~ -typedef wil::unique_struct unique_prop_variant; - -unique_prop_variant propvariant; -SomeFunction(&propvariant); -~~~ -*/ -template -class unique_struct : public struct_t -{ - using closer = details::close_invoker; - -public: - //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified - unique_struct() - { - call_init(use_default_init_fn()); - } - - //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t - explicit unique_struct(const struct_t& other) WI_NOEXCEPT : struct_t(other) - { - } - - //! Initializes the managed struct by taking the ownership of the other managed struct - //! Then resets the other managed struct by calling the custom close function - unique_struct(unique_struct&& other) WI_NOEXCEPT : struct_t(other.release()) - { - } - - //! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct - //! Then resets the other managed struct by calling the custom close function - unique_struct& operator=(unique_struct&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(other.release()); - } - return *this; - } - - //! Calls the custom close function - ~unique_struct() WI_NOEXCEPT - { - closer::close(this); - } - - void reset(const unique_struct&) = delete; - - //! Resets this managed struct by calling the custom close function and begins management of the other struct - void reset(const struct_t& other) WI_NOEXCEPT - { - closer::close_reset(this); - struct_t::operator=(other); - } - - //! Resets this managed struct by calling the custom close function - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is - //! specified - void reset() WI_NOEXCEPT - { - closer::close(this); - call_init(use_default_init_fn()); - } - - void swap(struct_t&) = delete; - - //! Swaps the managed structs - void swap(unique_struct& other) WI_NOEXCEPT - { - struct_t self(*this); - struct_t::operator=(other); - *(other.addressof()) = self; - } - - //! Returns the managed struct - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is - //! specified - struct_t release() WI_NOEXCEPT - { - struct_t value(*this); - call_init(use_default_init_fn()); - return value; - } - - //! Returns address of the managed struct - struct_t* addressof() WI_NOEXCEPT - { - return this; - } - - //! Resets this managed struct by calling the custom close function - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is - //! specified. - //! Returns address of the managed struct - struct_t* reset_and_addressof() WI_NOEXCEPT - { - reset(); - return this; - } - - unique_struct(const unique_struct&) = delete; - unique_struct& operator=(const unique_struct&) = delete; - unique_struct& operator=(const struct_t&) = delete; - -private: - typedef typename wistd::is_same::type use_default_init_fn; - - void call_init(wistd::true_type) - { - // Suppress '-Wnontrivial-memcall' with 'static_cast' - RtlZeroMemory(static_cast(this), sizeof(*this)); - } - - void call_init(wistd::false_type) - { - init_fn(this); - } -}; - -struct empty_deleter -{ - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const - { - static_assert( - !details::needs_destruction_v, - "Resource type has a non-trivial destructor, but is used in a context where its destructor will not be run"); - } -}; - -/** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that may need to be -freed. The intended use for this RAII type would be to capture out params from API like IPropertyValue::GetStringArray. This class -also maintains the size of the array, so it can iterate over the members and deallocate them before it deallocates the base array -pointer. - -If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send pull requests -to [GitHub](https://github.com/microsoft/wil/). Otherwise, if the type is local to your project, declare it locally. - -@tparam ValueType: The type of array you want to manage. -@tparam ArrayDeleter: The type of the function to clean up the array. Takes one parameter of type T[] or T*. Return values are - ignored. This is called in the destructor and reset functions. -@tparam ElementDeleter: The type of the function to clean up the array elements. Takes one parameter of type T. Return values are - ignored. This is called in the destructor and reset functions. - -~~~ -void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**); - -struct not_my_deleter -{ -void operator()(NOTMYTYPE p) const -{ -destroy(p); -} -}; - -wil::unique_any_array_ptr myArray; -GetSomeArray(myArray.size_address(), &myArray); -~~~ */ -template -class unique_any_array_ptr -{ -public: - typedef ValueType value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef ValueType* pointer; - typedef const ValueType* const_pointer; - typedef ValueType& reference; - typedef const ValueType& const_reference; - - typedef ValueType* iterator; - typedef const ValueType* const_iterator; - - unique_any_array_ptr() = default; - unique_any_array_ptr(const unique_any_array_ptr&) = delete; - unique_any_array_ptr& operator=(const unique_any_array_ptr&) = delete; - - unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT - { - } - - unique_any_array_ptr& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - return *this; - } - - unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size) - { - } - - unique_any_array_ptr(unique_any_array_ptr&& other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size) - { - other.m_ptr = nullptr; - other.m_size = size_type{}; - } - - unique_any_array_ptr& operator=(unique_any_array_ptr&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - swap(other); - } - return *this; - } - - ~unique_any_array_ptr() WI_NOEXCEPT - { - reset(); - } - - void swap(unique_any_array_ptr& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - auto size = m_size; - m_ptr = other.m_ptr; - m_size = other.m_size; - other.m_ptr = ptr; - other.m_size = size; - } - - WI_NODISCARD iterator begin() WI_NOEXCEPT - { - return (iterator(m_ptr)); - } - - WI_NODISCARD const_iterator begin() const WI_NOEXCEPT - { - return (const_iterator(m_ptr)); - } - - WI_NODISCARD iterator end() WI_NOEXCEPT - { - return (iterator(m_ptr + m_size)); - } - - WI_NODISCARD const_iterator end() const WI_NOEXCEPT - { - return (const_iterator(m_ptr + m_size)); - } - - WI_NODISCARD const_iterator cbegin() const WI_NOEXCEPT - { - return (begin()); - } - - WI_NODISCARD const_iterator cend() const WI_NOEXCEPT - { - return (end()); - } - - WI_NODISCARD size_type size() const WI_NOEXCEPT - { - return (m_size); - } - - WI_NODISCARD bool empty() const WI_NOEXCEPT - { - return (size() == size_type{}); - } - - WI_NODISCARD reference operator[](size_type position) - { - WI_ASSERT(position < m_size); - _Analysis_assume_(position < m_size); - return (m_ptr[position]); - } - - WI_NODISCARD const_reference operator[](size_type position) const - { - WI_ASSERT(position < m_size); - _Analysis_assume_(position < m_size); - return (m_ptr[position]); - } - - WI_NODISCARD reference front() - { - WI_ASSERT(!empty()); - return (m_ptr[0]); - } - - WI_NODISCARD const_reference front() const - { - WI_ASSERT(!empty()); - return (m_ptr[0]); - } - - WI_NODISCARD reference back() - { - WI_ASSERT(!empty()); - return (m_ptr[m_size - 1]); - } - - WI_NODISCARD const_reference back() const - { - WI_ASSERT(!empty()); - return (m_ptr[m_size - 1]); - } - - WI_NODISCARD ValueType* data() WI_NOEXCEPT - { - return (m_ptr); - } - - WI_NODISCARD const ValueType* data() const WI_NOEXCEPT - { - return (m_ptr); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return m_ptr; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != pointer()); - } - - pointer release() WI_NOEXCEPT - { - auto result = m_ptr; - m_ptr = nullptr; - m_size = size_type{}; - return result; - } - - void reset() WI_NOEXCEPT - { - if (m_ptr) - { - reset_array(ElementDeleter()); - ArrayDeleter()(m_ptr); - m_ptr = nullptr; - m_size = size_type{}; - } - } - - void reset(pointer ptr, size_t size) WI_NOEXCEPT - { - reset(); - m_ptr = ptr; - m_size = size; - } - - pointer* addressof() WI_NOEXCEPT - { - return &m_ptr; - } - - pointer* put() WI_NOEXCEPT - { - reset(); - return addressof(); - } - - pointer* operator&() WI_NOEXCEPT - { - return put(); - } - - size_type* size_address() WI_NOEXCEPT - { - return &m_size; - } - - template - struct size_address_ptr - { - unique_any_array_ptr& wrapper; - TSize size{}; - bool replace = true; - - size_address_ptr(_Inout_ unique_any_array_ptr& output) : wrapper(output) - { - } - - size_address_ptr(size_address_ptr&& other) WI_NOEXCEPT : wrapper(other.wrapper), size(other.size) - { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator TSize*() - { - WI_ASSERT(replace); - return &size; - } - - ~size_address_ptr() - { - if (replace) - { - *wrapper.size_address() = static_cast(size); - } - } - - size_address_ptr(size_address_ptr const& other) = delete; - size_address_ptr& operator=(size_address_ptr const& other) = delete; - }; - - template - size_address_ptr size_address() WI_NOEXCEPT - { - return size_address_ptr(*this); - } - -private: - pointer m_ptr = nullptr; - size_type m_size{}; - - void reset_array(const empty_deleter&) - { - } - - template - void reset_array(const T& deleter) - { - for (auto& element : make_range(m_ptr, m_size)) - { - deleter(element); - } - } -}; - -// forward declaration -template -class com_ptr_t; - -/// @cond -namespace details -{ - template - struct unique_any_array_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - UniqueAnyType::policy::close_reset(p); - } - }; - - template - struct unique_struct_array_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T& p) const - { - close_invoker::close(&p); - } - }; - - struct com_unknown_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - if (p) - { - p->Release(); + deleter(element); } } }; - template - struct element_traits + // forward declaration + template class com_ptr_t; + + /// @cond + namespace details { - typedef empty_deleter deleter; - typedef T type; - }; - - template - struct element_traits> - { - typedef unique_any_array_deleter> deleter; - typedef typename unique_any_t::pointer type; - }; - - template - struct element_traits> - { - typedef com_unknown_deleter deleter; - typedef T* type; - }; - - template - struct element_traits> - { - typedef unique_struct_array_deleter deleter; - typedef struct_t type; - }; -} // namespace details -/// @endcond - -template -using unique_array_ptr = - unique_any_array_ptr::type, ArrayDeleter, typename details::element_traits::deleter>; - -/** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`. -This struct provides a standard wrapper for calling a platform function to deallocate memory held by a -`wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>. - -Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an -array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely. -@code -EXTERN_C VOID WINAPI MyDllFreeMemory(void* p); -EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString); -EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing); -template -using unique_mydll_ptr = wistd::unique_ptr>; -HRESULT Test() -{ -unique_mydll_ptr dllString; -unique_mydll_ptr thing; -RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString))); -RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing))); -if (thing->Member) -{ -// ... -} -return S_OK; -} -@endcode -*/ -template -struct function_deleter -{ - template - void operator()(_Frees_ptr_opt_ T* toFree) const - { - TDeleter(toFree); - } -}; - -/** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface. -By comparison, unique_any_t has the requirement that the close function must be static. This works for functions -such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface, -unique_com_token can be used. - -@tparam interface_t A COM interface pointer that will manage this resource type. -@tparam token_t The token type that relates to the COM interface management functions. -@tparam close_fn_t The type of the function that is called when the resource is destroyed. -@tparam close_fn The function used to destroy the associated resource. This function should have the signature - void(interface_t* source, token_t token). -@tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t(). - -Example -~~~ -void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token) -{ -source->MyCloseFunction(token); -} -using unique_my_interface_token = - wil::unique_com_token; -~~~ */ -template -class unique_com_token -{ -public: - unique_com_token() = default; - - unique_com_token(_In_opt_ interface_t* source, token_t token = invalid_token) WI_NOEXCEPT - { - reset(source, token); - } - - unique_com_token(unique_com_token&& other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token) - { - other.m_source = nullptr; - other.m_token = invalid_token; - } - - unique_com_token& operator=(unique_com_token&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + template struct unique_any_array_deleter { - reset(); - m_source = other.m_source; - m_token = other.m_token; + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T *p) const + { + UniqueAnyType::policy::close_reset(p); + } + }; + template struct unique_struct_array_deleter + { + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T &p) const + { + close_invoker::close(&p); + } + }; + + struct com_unknown_deleter + { + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T *p) const + { + if (p) + { + p->Release(); + } + } + }; + + template struct element_traits + { + typedef empty_deleter deleter; + typedef T type; + }; + + template struct element_traits> + { + typedef unique_any_array_deleter> deleter; + typedef typename unique_any_t::pointer type; + }; + + template struct element_traits> + { + typedef com_unknown_deleter deleter; + typedef T *type; + }; + + template + struct element_traits> + { + typedef unique_struct_array_deleter deleter; + typedef struct_t type; + }; + } // namespace details + /// @endcond + + template + using unique_array_ptr = unique_any_array_ptr::type, ArrayDeleter, + typename details::element_traits::deleter>; + + /** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`. + This struct provides a standard wrapper for calling a platform function to deallocate memory held by a + `wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>. + + Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an + array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely. + @code + EXTERN_C VOID WINAPI MyDllFreeMemory(void* p); + EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString); + EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing); + template + using unique_mydll_ptr = wistd::unique_ptr>; + HRESULT Test() + { + unique_mydll_ptr dllString; + unique_mydll_ptr thing; + RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString))); + RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing))); + if (thing->Member) + { + // ... + } + return S_OK; + } + @endcode + */ + template struct function_deleter + { + template void operator()(_Frees_ptr_opt_ T *toFree) const + { + TDeleter(toFree); + } + }; + + /** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface. + By comparison, unique_any_t has the requirement that the close function must be static. This works for functions + such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface, + unique_com_token can be used. + + @tparam interface_t A COM interface pointer that will manage this resource type. + @tparam token_t The token type that relates to the COM interface management functions. + @tparam close_fn_t The type of the function that is called when the resource is destroyed. + @tparam close_fn The function used to destroy the associated resource. This function should have the signature + void(interface_t* source, token_t token). + @tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t(). + + Example + ~~~ + void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token) + { + source->MyCloseFunction(token); + } + using unique_my_interface_token = + wil::unique_com_token; + ~~~ */ + template + class unique_com_token + { + public: + unique_com_token() = default; + + unique_com_token(_In_opt_ interface_t *source, token_t token = invalid_token) WI_NOEXCEPT + { + reset(source, token); + } + + unique_com_token(unique_com_token &&other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token) + { other.m_source = nullptr; other.m_token = invalid_token; } - return *this; - } - ~unique_com_token() WI_NOEXCEPT - { - reset(); - } - - //! Determine if the underlying source and token are valid - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_token != invalid_token) && m_source; - } - - //! Associates a new source and releases the existing token if valid - void associate(_In_opt_ interface_t* source) WI_NOEXCEPT - { - reset(source, invalid_token); - } - - //! Assigns a new source and token - void reset(_In_opt_ interface_t* source, token_t token) WI_NOEXCEPT - { - WI_ASSERT(source || (token == invalid_token)); - - // Determine if we need to call the close function on our previous token. - if (m_token != invalid_token) + unique_com_token &operator=(unique_com_token &&other) WI_NOEXCEPT { - if ((m_source != source) || (m_token != token)) + if (this != wistd::addressof(other)) { - wistd::invoke(close_fn, m_source, m_token); + reset(); + m_source = other.m_source; + m_token = other.m_token; + + other.m_source = nullptr; + other.m_token = invalid_token; } + return *this; } - m_token = token; - - // Assign our new source and manage the reference counts - if (m_source != source) - { - auto oldSource = m_source; - m_source = source; - - if (m_source) - { - m_source->AddRef(); - } - - if (oldSource) - { - oldSource->Release(); - } - } - } - - //! Assigns a new token without modifying the source; associate must be called first - void reset(token_t token) WI_NOEXCEPT - { - reset(m_source, token); - } - - //! Closes the token and the releases the reference to the source - void reset() WI_NOEXCEPT - { - reset(nullptr, invalid_token); - } - - //! Exchanges values with another managed token - void swap(unique_com_token& other) WI_NOEXCEPT - { - wistd::swap_wil(m_source, other.m_source); - wistd::swap_wil(m_token, other.m_token); - } - - //! Releases the held token to the caller without closing it and releases the reference to the source. - //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated - token_t release() WI_NOEXCEPT - { - auto token = m_token; - m_token = invalid_token; - reset(); - return token; - } - - //! Returns address of the managed token; associate must be called first - token_t* addressof() WI_NOEXCEPT - { - WI_ASSERT(m_source); - return &m_token; - } - - //! Releases the held token and allows attaching a new token; associate must be called first - token_t* put() WI_NOEXCEPT - { - reset(invalid_token); - return addressof(); - } - - //! Releases the held token and allows attaching a new token; associate must be called first - token_t* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Retrieves the token - WI_NODISCARD token_t get() const WI_NOEXCEPT - { - return m_token; - } - - unique_com_token(const unique_com_token&) = delete; - unique_com_token& operator=(const unique_com_token&) = delete; - -private: - interface_t* m_source = nullptr; - token_t m_token = invalid_token; -}; - -/** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM interface. -This allows implementing an RAII type that can call a Close() method (think IClosable) or a SetSite(nullptr) -method (think IObjectWithSite) or some other method when a basic interface call is required as part of the RAII contract. -see wil::com_set_site in wil/com.h for the IObjectWithSite support. - -@tparam interface_t A COM interface pointer that provides context to make the call. -@tparam close_fn_t The type of the function that is called to invoke the method. -@tparam close_fn The function used to invoke the interface method. This function should have the signature - void(interface_t* source). - -Example -~~~ -void __stdcall CloseIClosable(IClosable* source) -{ -source->Close(); -} -using unique_closable_call = wil::unique_com_call; -~~~ */ -template -class unique_com_call -{ -public: - unique_com_call() = default; - - explicit unique_com_call(_In_opt_ interface_t* ptr) WI_NOEXCEPT - { - reset(ptr); - } - - unique_com_call(unique_com_call&& other) WI_NOEXCEPT - { - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - } - - unique_com_call& operator=(unique_com_call&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + ~unique_com_token() WI_NOEXCEPT { reset(); + } + + //! Determine if the underlying source and token are valid + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return (m_token != invalid_token) && m_source; + } + + //! Associates a new source and releases the existing token if valid + void associate(_In_opt_ interface_t *source) WI_NOEXCEPT + { + reset(source, invalid_token); + } + + //! Assigns a new source and token + void reset(_In_opt_ interface_t *source, token_t token) WI_NOEXCEPT + { + WI_ASSERT(source || (token == invalid_token)); + + // Determine if we need to call the close function on our previous token. + if (m_token != invalid_token) + { + if ((m_source != source) || (m_token != token)) + { + wistd::invoke(close_fn, m_source, m_token); + } + } + + m_token = token; + + // Assign our new source and manage the reference counts + if (m_source != source) + { + auto oldSource = m_source; + m_source = source; + + if (m_source) + { + m_source->AddRef(); + } + + if (oldSource) + { + oldSource->Release(); + } + } + } + + //! Assigns a new token without modifying the source; associate must be called first + void reset(token_t token) WI_NOEXCEPT + { + reset(m_source, token); + } + + //! Closes the token and the releases the reference to the source + void reset() WI_NOEXCEPT + { + reset(nullptr, invalid_token); + } + + //! Exchanges values with another managed token + void swap(unique_com_token &other) WI_NOEXCEPT + { + wistd::swap_wil(m_source, other.m_source); + wistd::swap_wil(m_token, other.m_token); + } + + //! Releases the held token to the caller without closing it and releases the reference to the source. + //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated + token_t release() WI_NOEXCEPT + { + auto token = m_token; + m_token = invalid_token; + reset(); + return token; + } + + //! Returns address of the managed token; associate must be called first + token_t *addressof() WI_NOEXCEPT + { + WI_ASSERT(m_source); + return &m_token; + } + + //! Releases the held token and allows attaching a new token; associate must be called first + token_t *put() WI_NOEXCEPT + { + reset(invalid_token); + return addressof(); + } + + //! Releases the held token and allows attaching a new token; associate must be called first + token_t *operator&() WI_NOEXCEPT + { + return put(); + } + + //! Retrieves the token + WI_NODISCARD token_t get() const WI_NOEXCEPT + { + return m_token; + } + + unique_com_token(const unique_com_token &) = delete; + unique_com_token &operator=(const unique_com_token &) = delete; + + private: + interface_t *m_source = nullptr; + token_t m_token = invalid_token; + }; + + /** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM + interface. This allows implementing an RAII type that can call a Close() method (think IClosable) or a + SetSite(nullptr) method (think IObjectWithSite) or some other method when a basic interface call is required as part + of the RAII contract. see wil::com_set_site in wil/com.h for the IObjectWithSite support. + + @tparam interface_t A COM interface pointer that provides context to make the call. + @tparam close_fn_t The type of the function that is called to invoke the method. + @tparam close_fn The function used to invoke the interface method. This function should have the signature + void(interface_t* source). + + Example + ~~~ + void __stdcall CloseIClosable(IClosable* source) + { + source->Close(); + } + using unique_closable_call = wil::unique_com_call; + ~~~ */ + template class unique_com_call + { + public: + unique_com_call() = default; + + explicit unique_com_call(_In_opt_ interface_t *ptr) WI_NOEXCEPT + { + reset(ptr); + } + + unique_com_call(unique_com_call &&other) WI_NOEXCEPT + { m_ptr = other.m_ptr; other.m_ptr = nullptr; } - return *this; - } - ~unique_com_call() WI_NOEXCEPT - { - reset(); - } - - //! Assigns an interface to make a given call on - void reset(_In_opt_ interface_t* ptr = nullptr) WI_NOEXCEPT - { - if (ptr != m_ptr) + unique_com_call &operator=(unique_com_call &&other) WI_NOEXCEPT { - auto oldSource = m_ptr; - m_ptr = ptr; - if (m_ptr) + if (this != wistd::addressof(other)) { - m_ptr->AddRef(); - } - if (oldSource) - { - details::close_invoker::close(oldSource); - oldSource->Release(); + reset(); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; } + return *this; } - } - //! Exchanges values with another class - void swap(unique_com_call& other) WI_NOEXCEPT - { - wistd::swap_wil(m_ptr, other.m_ptr); - } - - //! Cancel the interface call that this class was expected to make - void release() WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = nullptr; - if (ptr) - { - ptr->Release(); - } - } - - //! Returns true if the call this class was expected to make is still outstanding - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != nullptr); - } - - //! Returns address of the internal interface - interface_t** addressof() WI_NOEXCEPT - { - return &m_ptr; - } - - //! Releases the held interface (first performing the interface call if required) - //! and allows attaching a new interface - interface_t** put() WI_NOEXCEPT - { - reset(); - return addressof(); - } - - //! Releases the held interface (first performing the interface call if required) - //! and allows attaching a new interface - interface_t** operator&() WI_NOEXCEPT - { - return put(); - } - - unique_com_call(const unique_com_call&) = delete; - unique_com_call& operator=(const unique_com_call&) = delete; - -private: - interface_t* m_ptr = nullptr; -}; - -/** Use unique_call to define an RAII type that demands a particular parameter-less global function be called. -This allows implementing a RAII types that can call methods like CoUninitialize. - -@tparam close_fn_t The type of the function that is called to invoke the call. -@tparam close_fn The function used to invoke the call. This function should have the signature void(). -@tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset. - -Example -~~~ -void __stdcall CoUninitializeFunction() -{ -::CoUninitialize(); -} -using unique_couninitialize_call = wil::unique_call; -~~~ */ -template -class unique_call -{ -public: - unique_call() = default; - - explicit unique_call(bool call) WI_NOEXCEPT : m_call(call) - { - } - - unique_call(unique_call&& other) WI_NOEXCEPT - { - m_call = other.m_call; - other.m_call = false; - } - - unique_call& operator=(unique_call&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + ~unique_com_call() WI_NOEXCEPT { reset(); + } + + //! Assigns an interface to make a given call on + void reset(_In_opt_ interface_t *ptr = nullptr) WI_NOEXCEPT + { + if (ptr != m_ptr) + { + auto oldSource = m_ptr; + m_ptr = ptr; + if (m_ptr) + { + m_ptr->AddRef(); + } + if (oldSource) + { + details::close_invoker::close(oldSource); + oldSource->Release(); + } + } + } + + //! Exchanges values with another class + void swap(unique_com_call &other) WI_NOEXCEPT + { + wistd::swap_wil(m_ptr, other.m_ptr); + } + + //! Cancel the interface call that this class was expected to make + void release() WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = nullptr; + if (ptr) + { + ptr->Release(); + } + } + + //! Returns true if the call this class was expected to make is still outstanding + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != nullptr); + } + + //! Returns address of the internal interface + interface_t **addressof() WI_NOEXCEPT + { + return &m_ptr; + } + + //! Releases the held interface (first performing the interface call if required) + //! and allows attaching a new interface + interface_t **put() WI_NOEXCEPT + { + reset(); + return addressof(); + } + + //! Releases the held interface (first performing the interface call if required) + //! and allows attaching a new interface + interface_t **operator&() WI_NOEXCEPT + { + return put(); + } + + unique_com_call(const unique_com_call &) = delete; + unique_com_call &operator=(const unique_com_call &) = delete; + + private: + interface_t *m_ptr = nullptr; + }; + + /** Use unique_call to define an RAII type that demands a particular parameter-less global function be called. + This allows implementing a RAII types that can call methods like CoUninitialize. + + @tparam close_fn_t The type of the function that is called to invoke the call. + @tparam close_fn The function used to invoke the call. This function should have the signature void(). + @tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset. + + Example + ~~~ + void __stdcall CoUninitializeFunction() + { + ::CoUninitialize(); + } + using unique_couninitialize_call = wil::unique_call; + ~~~ */ + template class unique_call + { + public: + unique_call() = default; + + explicit unique_call(bool call) WI_NOEXCEPT : m_call(call) + { + } + + unique_call(unique_call &&other) WI_NOEXCEPT + { m_call = other.m_call; other.m_call = false; } - return *this; - } - ~unique_call() WI_NOEXCEPT - { - reset(); - } - - //! Assigns a new ptr and token - void reset() WI_NOEXCEPT - { - auto call = m_call; - m_call = false; - if (call) + unique_call &operator=(unique_call &&other) WI_NOEXCEPT { - close_fn(); - } - } - - //! Exchanges values with raii class - void swap(unique_call& other) WI_NOEXCEPT - { - wistd::swap_wil(m_call, other.m_call); - } - - //! Make the interface call that was expected of this class - void activate() WI_NOEXCEPT - { - m_call = true; - } - - //! Do not make the interface call that was expected of this class - void release() WI_NOEXCEPT - { - m_call = false; - } - - //! Returns true if the call that was expected is still outstanding - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_call; - } - - unique_call(const unique_call&) = delete; - unique_call& operator=(const unique_call&) = delete; - -private: - bool m_call = default_value; -}; - -// str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. -// Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any unique_any_t -// that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and similar). -// An overload for std::wstring is available in stl.h. -inline PCWSTR str_raw_ptr(PCWSTR str) -{ - return str; -} - -template -PCWSTR str_raw_ptr(const unique_any_t& ua) -{ - return str_raw_ptr(ua.get()); -} - -#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -/// @cond -namespace details -{ - // Forward declaration - template - struct string_maker; - - // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present - // in the input buffer, it is overwritten. - template - HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount) - { - size_t lengthRequiredWithoutNull{}; - for (auto& string : make_range(strList, strCount)) - { - lengthRequiredWithoutNull += string ? wcslen(string) : 0; - } - - details::string_maker maker; - RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); - - auto buffer = maker.buffer(); - auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; - for (auto& string : make_range(strList, strCount)) - { - if (string) + if (this != wistd::addressof(other)) { - RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); + reset(); + m_call = other.m_call; + other.m_call = false; + } + return *this; + } + + ~unique_call() WI_NOEXCEPT + { + reset(); + } + + //! Assigns a new ptr and token + void reset() WI_NOEXCEPT + { + auto call = m_call; + m_call = false; + if (call) + { + close_fn(); } } - result = maker.release(); - return S_OK; - } + //! Exchanges values with raii class + void swap(unique_call &other) WI_NOEXCEPT + { + wistd::swap_wil(m_call, other.m_call); + } - // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly - template - HRESULT str_build_nothrow(string_type& result, Strings... strings) + //! Make the interface call that was expected of this class + void activate() WI_NOEXCEPT + { + m_call = true; + } + + //! Do not make the interface call that was expected of this class + void release() WI_NOEXCEPT + { + m_call = false; + } + + //! Returns true if the call that was expected is still outstanding + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + unique_call(const unique_call &) = delete; + unique_call &operator=(const unique_call &) = delete; + + private: + bool m_call = default_value; + }; + + // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. + // Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any + // unique_any_t that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and + // similar). An overload for std::wstring is available in stl.h. + inline PCWSTR str_raw_ptr(PCWSTR str) { - PCWSTR localStrings[] = {strings...}; - return str_build_nothrow(result, localStrings, sizeof...(Strings)); + return str; } -} // namespace details -/// @endcond -// Concatenate any number of strings together and store it in an automatically allocated string. If a string is present -// in the input buffer, the remaining strings are appended to it. -template -HRESULT str_concat_nothrow(string_type& buffer, const strings&... str) -{ - static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); - return details::str_build_nothrow(buffer, details::string_maker::get(buffer), str_raw_ptr(str)...); -} + template PCWSTR str_raw_ptr(const unique_any_t &ua) + { + return str_raw_ptr(ua.get()); + } + +#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) + /// @cond + namespace details + { + // Forward declaration + template struct string_maker; + + // Concatenate any number of strings together and store it in an automatically allocated string. If a string is + // present in the input buffer, it is overwritten. + template + HRESULT str_build_nothrow(string_type &result, _In_reads_(strCount) PCWSTR *strList, size_t strCount) + { + size_t lengthRequiredWithoutNull{}; + for (auto &string : make_range(strList, strCount)) + { + lengthRequiredWithoutNull += string ? wcslen(string) : 0; + } + + details::string_maker maker; + RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); + + auto buffer = maker.buffer(); + auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; + for (auto &string : make_range(strList, strCount)) + { + if (string) + { + RETURN_IF_FAILED( + StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); + } + } + + result = maker.release(); + return S_OK; + } + + // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that + // cleanly + template + HRESULT str_build_nothrow(string_type &result, Strings... strings) + { + PCWSTR localStrings[] = {strings...}; + return str_build_nothrow(result, localStrings, sizeof...(Strings)); + } + } // namespace details + /// @endcond + + // Concatenate any number of strings together and store it in an automatically allocated string. If a string is + // present in the input buffer, the remaining strings are appended to it. + template + HRESULT str_concat_nothrow(string_type &buffer, const strings &...str) + { + static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); + return details::str_build_nothrow(buffer, details::string_maker::get(buffer), str_raw_ptr(str)...); + } #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) #ifdef WIL_ENABLE_EXCEPTIONS -// Concatenate any number of strings together and store it in an automatically allocated string. -template -string_type str_concat(arguments&&... args) -{ - string_type result{}; - THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); - return result; -} + // Concatenate any number of strings together and store it in an automatically allocated string. + template string_type str_concat(arguments &&...args) + { + string_type result{}; + THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -// Concatenate any number of strings together and store it in an automatically allocated string. -template -string_type str_concat_failfast(arguments&&... args) -{ - string_type result{}; - FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); - return result; -} + // Concatenate any number of strings together and store it in an automatically allocated string. + template string_type str_concat_failfast(arguments &&...args) + { + string_type result{}; + FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); + return result; + } #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -/// @cond -namespace details -{ - // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format - // arguments that StringCchPrintfExW takes. - template - HRESULT str_vprintf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, va_list& argsVL) + /// @cond + namespace details { - size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL); + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the + // same format arguments that StringCchPrintfExW takes. + template + HRESULT str_vprintf_nothrow(string_type &result, _Printf_format_string_ PCWSTR pszFormat, va_list &argsVL) + { + size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL); - string_maker maker; - RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); + string_maker maker; + RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); - auto buffer = maker.buffer(); - RETURN_IF_FAILED( - StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL)); + auto buffer = maker.buffer(); + RETURN_IF_FAILED(StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, + STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL)); - result = maker.release(); - return S_OK; + result = maker.release(); + return S_OK; + } + } // namespace details + /// @endcond + + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same + // format arguments that StringCchPrintfExW takes. + template + HRESULT str_printf_nothrow(string_type &result, _Printf_format_string_ PCWSTR pszFormat, ...) + { + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + return hr; } -} // namespace details -/// @endcond - -// Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format -// arguments that StringCchPrintfExW takes. -template -HRESULT str_printf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, ...) -{ - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - return hr; -} #ifdef WIL_ENABLE_EXCEPTIONS -// Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format -// arguments that StringCchPrintfExW takes. -template -string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, ...) -{ - string_type result{}; - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - THROW_IF_FAILED(hr); - return result; -} + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same + // format arguments that StringCchPrintfExW takes. + template string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, ...) + { + string_type result{}; + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + THROW_IF_FAILED(hr); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -// Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format -// arguments that StringCchPrintfExW takes. -template -string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, ...) -{ - string_type result{}; - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - FAIL_FAST_IF_FAILED(hr); - return result; -} + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same + // format arguments that StringCchPrintfExW takes. + template string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, ...) + { + string_type result{}; + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + FAIL_FAST_IF_FAILED(hr); + return result; + } #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) } // namespace wil #endif // __WIL_RESOURCE // Hash deferral function for unique_any_t -#if ((defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH)) || defined(WIL_DOXYGEN) +#if ((defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_RESOURCE_UNIQUE_HASH /// @endcond namespace std { -template -struct hash> -{ - WI_NODISCARD size_t operator()(wil::unique_any_t const& val) const + template struct hash> { - return (hash::pointer>()(val.get())); - } -}; + WI_NODISCARD size_t operator()(wil::unique_any_t const &val) const + { + return (hash::pointer>()(val.get())); + } + }; } // namespace std #endif // shared_any and weak_any implementation using STL header -#if (defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL)) || \ +#if (defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && \ + !defined(RESOURCE_SUPPRESS_STL)) || \ defined(WIL_DOXYGEN) /// @cond #define WIL_RESOURCE_STL @@ -1998,406 +1956,388 @@ struct hash> namespace wil { -template -class weak_any; + template class weak_any; -/// @cond -namespace details -{ - // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given - // resource_policy. It is separate from shared_any_t to allow a type-specific specialization class to plug - // into the inheritance chain between shared_any_t and shared_storage. This allows classes like shared_event - // to be a shared_any formed class, but also expose methods like SetEvent directly. - - template - class shared_storage + /// @cond + namespace details { - protected: - typedef UniqueT unique_t; - typedef typename unique_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - typedef shared_storage base_storage; + // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given + // resource_policy. It is separate from shared_any_t to allow a type-specific specialization class to plug + // into the inheritance chain between shared_any_t and shared_storage. This allows classes like shared_event + // to be a shared_any formed class, but also expose methods like SetEvent directly. - public: - shared_storage() = default; - - explicit shared_storage(pointer_storage ptr) + template class shared_storage { - if (policy::is_valid(ptr)) + protected: + typedef UniqueT unique_t; + typedef typename unique_t::policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef shared_storage base_storage; + + public: + shared_storage() = default; + + explicit shared_storage(pointer_storage ptr) { - m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + if (policy::is_valid(ptr)) + { + m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + } } - } - shared_storage(unique_t&& other) - { - if (other) + shared_storage(unique_t &&other) + { + if (other) + { + m_ptr = std::make_shared(wistd::move(other)); + } + } + + shared_storage(const shared_storage &other) WI_NOEXCEPT : m_ptr(other.m_ptr) + { + } + + shared_storage &operator=(const shared_storage &other) WI_NOEXCEPT + { + m_ptr = other.m_ptr; + return *this; + } + + shared_storage(shared_storage &&other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) + { + } + + shared_storage(std::shared_ptr const &ptr) : m_ptr(ptr) + { + } + + WI_NODISCARD bool is_valid() const WI_NOEXCEPT + { + return (m_ptr && m_ptr->is_valid()); + } + + void reset(pointer_storage ptr = policy::invalid_value()) + { + if (policy::is_valid(ptr)) + { + m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + } + else + { + m_ptr = nullptr; + } + } + + void reset(unique_t &&other) { m_ptr = std::make_shared(wistd::move(other)); } - } - shared_storage(const shared_storage& other) WI_NOEXCEPT : m_ptr(other.m_ptr) - { - } - - shared_storage& operator=(const shared_storage& other) WI_NOEXCEPT - { - m_ptr = other.m_ptr; - return *this; - } - - shared_storage(shared_storage&& other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr)) - { - } - - shared_storage(std::shared_ptr const& ptr) : m_ptr(ptr) - { - } - - WI_NODISCARD bool is_valid() const WI_NOEXCEPT - { - return (m_ptr && m_ptr->is_valid()); - } - - void reset(pointer_storage ptr = policy::invalid_value()) - { - if (policy::is_valid(ptr)) + void reset(wistd::nullptr_t) WI_NOEXCEPT { - m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + static_assert(wistd::is_same::value, + "reset(nullptr): valid only for handle types using nullptr as the invalid value"); + reset(); } - else + + template < + typename allow_t = typename policy::pointer_access, + typename wistd::enable_if::value, int>::type = 0> + WI_NODISCARD pointer get() const WI_NOEXCEPT { - m_ptr = nullptr; + return (m_ptr ? m_ptr->get() : policy::invalid_value()); } - } - void reset(unique_t&& other) + template < + typename allow_t = typename policy::pointer_access, + typename wistd::enable_if::value, int>::type = 0> + pointer_storage *addressof() + { + if (!m_ptr) + { + m_ptr = std::make_shared(); + } + return m_ptr->addressof(); + } + + WI_NODISCARD long int use_count() const WI_NOEXCEPT + { + return m_ptr.use_count(); + } + + protected: + void replace(shared_storage &&other) WI_NOEXCEPT + { + m_ptr = wistd::move(other.m_ptr); + } + + private: + template friend class ::wil::weak_any; + + std::shared_ptr m_ptr; + }; + } // namespace details + /// @endcond + + // This class when paired with shared_storage and an optional type-specific specialization class implements + // the same interface as STL's shared_ptr<> for resource handle types. It is both copyable and movable, supporting + // weak references and automatic closure of the handle upon release of the last shared_any. + + template class shared_any_t : public storage_t + { + public: + typedef typename storage_t::policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef typename storage_t::unique_t unique_t; + + // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base + // class + template + explicit shared_any_t(args_t &&...args) + __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) + : storage_t(wistd::forward(args)...) { - m_ptr = std::make_shared(wistd::move(other)); } - void reset(wistd::nullptr_t) WI_NOEXCEPT + shared_any_t(wistd::nullptr_t) WI_NOEXCEPT { - static_assert( - wistd::is_same::value, - "reset(nullptr): valid only for handle types using nullptr as the invalid value"); - reset(); + static_assert(wistd::is_same::value, + "nullptr constructor: valid only for handle types using nullptr as the invalid value"); + } + + shared_any_t(shared_any_t &&other) WI_NOEXCEPT : storage_t(wistd::move(other)) + { + } + + shared_any_t(const shared_any_t &other) WI_NOEXCEPT : storage_t(other) + { + } + + shared_any_t &operator=(shared_any_t &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + storage_t::replace(wistd::move(static_cast(other))); + } + return (*this); + } + + shared_any_t &operator=(const shared_any_t &other) WI_NOEXCEPT + { + storage_t::operator=(other); + return (*this); + } + + shared_any_t(unique_t &&other) : storage_t(wistd::move(other)) + { + } + + shared_any_t &operator=(unique_t &&other) + { + storage_t::reset(wistd::move(other)); + return (*this); + } + + shared_any_t &operator=(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, + "nullptr assignment: valid only for handle types using nullptr as the invalid value"); + storage_t::reset(); + return (*this); + } + + void swap(shared_any_t &other) WI_NOEXCEPT + { + shared_any_t self(wistd::move(*this)); + operator=(wistd::move(other)); + other = wistd::move(self); + } + + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return storage_t::is_valid(); + } + + pointer_storage *put() + { + static_assert(wistd::is_same::value, + "operator & is not available for this handle"); + storage_t::reset(); + return storage_t::addressof(); + } + + pointer_storage *operator&() + { + return put(); } - template < - typename allow_t = typename policy::pointer_access, - typename wistd::enable_if::value, int>::type = 0> WI_NODISCARD pointer get() const WI_NOEXCEPT { - return (m_ptr ? m_ptr->get() : policy::invalid_value()); + static_assert(!wistd::is_same::value, + "get(): the raw handle value is not available for this resource class"); + return storage_t::get(); } - template < - typename allow_t = typename policy::pointer_access, - typename wistd::enable_if::value, int>::type = 0> - pointer_storage* addressof() - { - if (!m_ptr) - { - m_ptr = std::make_shared(); - } - return m_ptr->addressof(); - } + // The following functions are publicly exposed by their inclusion in the base class - WI_NODISCARD long int use_count() const WI_NOEXCEPT - { - return m_ptr.use_count(); - } - - protected: - void replace(shared_storage&& other) WI_NOEXCEPT - { - m_ptr = wistd::move(other.m_ptr); - } - - private: - template - friend class ::wil::weak_any; - - std::shared_ptr m_ptr; + // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + // void reset(wistd::nullptr_t) WI_NOEXCEPT + // pointer_storage *addressof() WI_NOEXCEPT // (note: not exposed for opaque + // resource types) }; -} // namespace details -/// @endcond -// This class when paired with shared_storage and an optional type-specific specialization class implements -// the same interface as STL's shared_ptr<> for resource handle types. It is both copyable and movable, supporting -// weak references and automatic closure of the handle upon release of the last shared_any. - -template -class shared_any_t : public storage_t -{ -public: - typedef typename storage_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - typedef typename storage_t::unique_t unique_t; - - // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base class - template - explicit shared_any_t(args_t&&... args) __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) : - storage_t(wistd::forward(args)...) + template void swap(shared_any_t &left, shared_any_t &right) WI_NOEXCEPT { + left.swap(right); } - shared_any_t(wistd::nullptr_t) WI_NOEXCEPT + template + bool operator==(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT { - static_assert( - wistd::is_same::value, - "nullptr constructor: valid only for handle types using nullptr as the invalid value"); + return (left.get() == right.get()); } - shared_any_t(shared_any_t&& other) WI_NOEXCEPT : storage_t(wistd::move(other)) + template bool operator==(const shared_any_t &left, wistd::nullptr_t) WI_NOEXCEPT { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !left; } - shared_any_t(const shared_any_t& other) WI_NOEXCEPT : storage_t(other) + template bool operator==(wistd::nullptr_t, const shared_any_t &right) WI_NOEXCEPT { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !right; } - shared_any_t& operator=(shared_any_t&& other) WI_NOEXCEPT + template + bool operator!=(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT { - if (this != wistd::addressof(other)) + return (!(left.get() == right.get())); + } + + template bool operator!=(const shared_any_t &left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !!left; + } + + template bool operator!=(wistd::nullptr_t, const shared_any_t &right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, + "the resource class does not use nullptr as an invalid value"); + return !!right; + } + + template + bool operator<(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT + { + return (left.get() < right.get()); + } + + template + bool operator>=(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT + { + return (!(left < right)); + } + + template + bool operator>(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT + { + return (right < left); + } + + template + bool operator<=(const shared_any_t &left, const shared_any_t &right) WI_NOEXCEPT + { + return (!(right < left)); + } + + // This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() + // acquire semantics to shared_any. + + template class weak_any + { + public: + typedef SharedT shared_t; + + weak_any() WI_NOEXCEPT { - storage_t::replace(wistd::move(static_cast(other))); } - return (*this); - } - shared_any_t& operator=(const shared_any_t& other) WI_NOEXCEPT + weak_any(const shared_t &other) WI_NOEXCEPT : m_weakPtr(other.m_ptr) + { + } + + weak_any(const weak_any &other) WI_NOEXCEPT : m_weakPtr(other.m_weakPtr) + { + } + + weak_any &operator=(const weak_any &right) WI_NOEXCEPT + { + m_weakPtr = right.m_weakPtr; + return (*this); + } + + weak_any &operator=(const shared_t &right) WI_NOEXCEPT + { + m_weakPtr = right.m_ptr; + return (*this); + } + + void reset() WI_NOEXCEPT + { + m_weakPtr.reset(); + } + + void swap(weak_any &other) WI_NOEXCEPT + { + m_weakPtr.swap(other.m_weakPtr); + } + + WI_NODISCARD bool expired() const WI_NOEXCEPT + { + return m_weakPtr.expired(); + } + + WI_NODISCARD shared_t lock() const WI_NOEXCEPT + { + return shared_t(m_weakPtr.lock()); + } + + private: + std::weak_ptr m_weakPtr; + }; + + template void swap(weak_any &left, weak_any &right) WI_NOEXCEPT { - storage_t::operator=(other); - return (*this); + left.swap(right); } - shared_any_t(unique_t&& other) : storage_t(wistd::move(other)) - { - } - - shared_any_t& operator=(unique_t&& other) - { - storage_t::reset(wistd::move(other)); - return (*this); - } - - shared_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert( - wistd::is_same::value, - "nullptr assignment: valid only for handle types using nullptr as the invalid value"); - storage_t::reset(); - return (*this); - } - - void swap(shared_any_t& other) WI_NOEXCEPT - { - shared_any_t self(wistd::move(*this)); - operator=(wistd::move(other)); - other = wistd::move(self); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return storage_t::is_valid(); - } - - pointer_storage* put() - { - static_assert( - wistd::is_same::value, - "operator & is not available for this handle"); - storage_t::reset(); - return storage_t::addressof(); - } - - pointer_storage* operator&() - { - return put(); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - static_assert( - !wistd::is_same::value, - "get(): the raw handle value is not available for this resource class"); - return storage_t::get(); - } - - // The following functions are publicly exposed by their inclusion in the base class - - // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT - // void reset(wistd::nullptr_t) WI_NOEXCEPT - // pointer_storage *addressof() WI_NOEXCEPT // (note: not exposed for opaque resource types) -}; - -template -void swap(shared_any_t& left, shared_any_t& right) WI_NOEXCEPT -{ - left.swap(right); -} - -template -bool operator==(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (left.get() == right.get()); -} - -template -bool operator==(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !left; -} - -template -bool operator==(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !right; -} - -template -bool operator!=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (!(left.get() == right.get())); -} - -template -bool operator!=(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !!left; -} - -template -bool operator!=(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT -{ - static_assert( - wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, - "the resource class does not use nullptr as an invalid value"); - return !!right; -} - -template -bool operator<(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (left.get() < right.get()); -} - -template -bool operator>=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (!(left < right)); -} - -template -bool operator>(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (right < left); -} - -template -bool operator<=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT -{ - return (!(right < left)); -} - -// This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() acquire semantics -// to shared_any. - -template -class weak_any -{ -public: - typedef SharedT shared_t; - - weak_any() WI_NOEXCEPT - { - } - - weak_any(const shared_t& other) WI_NOEXCEPT : m_weakPtr(other.m_ptr) - { - } - - weak_any(const weak_any& other) WI_NOEXCEPT : m_weakPtr(other.m_weakPtr) - { - } - - weak_any& operator=(const weak_any& right) WI_NOEXCEPT - { - m_weakPtr = right.m_weakPtr; - return (*this); - } - - weak_any& operator=(const shared_t& right) WI_NOEXCEPT - { - m_weakPtr = right.m_ptr; - return (*this); - } - - void reset() WI_NOEXCEPT - { - m_weakPtr.reset(); - } - - void swap(weak_any& other) WI_NOEXCEPT - { - m_weakPtr.swap(other.m_weakPtr); - } - - WI_NODISCARD bool expired() const WI_NOEXCEPT - { - return m_weakPtr.expired(); - } - - WI_NODISCARD shared_t lock() const WI_NOEXCEPT - { - return shared_t(m_weakPtr.lock()); - } - -private: - std::weak_ptr m_weakPtr; -}; - -template -void swap(weak_any& left, weak_any& right) WI_NOEXCEPT -{ - left.swap(right); -} - -template -using shared_any = shared_any_t>; + template using shared_any = shared_any_t>; } // namespace wil #endif -#if (defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH)) || \ +#if (defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && \ + !defined(__WIL_RESOURCE_SHARED_HASH)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_RESOURCE_SHARED_HASH /// @endcond namespace std { -template -struct hash> -{ - WI_NODISCARD size_t operator()(wil::shared_any_t const& val) const + template struct hash> { - return (hash::pointer>()(val.get())); - } -}; + WI_NODISCARD size_t operator()(wil::shared_any_t const &val) const + { + return (hash::pointer>()(val.get())); + } + }; } // namespace std #endif @@ -2407,1610 +2347,1691 @@ namespace wil #if (defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED)) || defined(WIL_DOXYGEN) /// @cond #define __WIL__NOTHROW_T_DEFINED -/// @endcond -/** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation failure. -`wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following: -- It returns `wistd::unique_ptr`, rather than `std::unique_ptr` -- It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception + /// @endcond + /** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation + failure. `wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following: + - It returns `wistd::unique_ptr`, rather than `std::unique_ptr` + - It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception -Note that `wil::make_unique_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may -throw in its constructor. -~~~ -auto foo = wil::make_unique_nothrow(fooConstructorParam1, fooConstructorParam2); -if (foo) -{ -foo->Bar(); -} -~~~ -*/ -template -inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty>>::type make_unique_nothrow(_Types&&... _Args) -{ - return (wistd::unique_ptr<_Ty>(new (std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))); -} + Note that `wil::make_unique_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based + class that may throw in its constructor. + ~~~ + auto foo = wil::make_unique_nothrow(fooConstructorParam1, fooConstructorParam2); + if (foo) + { + foo->Bar(); + } + ~~~ + */ + template + inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty>>::type make_unique_nothrow( + _Types &&..._Args) + { + return (wistd::unique_ptr<_Ty>(new (std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))); + } -/** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon allocation failure. -See the overload of `wil::make_unique_nothrow()` for non-array types for more details. -~~~ -const size_t size = 42; -auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object -if (foos) -{ -for (auto& elem : wil::make_range(foos.get(), size)) -{ -elem.Bar(); -} -} -~~~ -*/ -template -inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty>>::type make_unique_nothrow( - size_t _Size) -{ - typedef typename wistd::remove_extent<_Ty>::type _Elem; - return (wistd::unique_ptr<_Ty>(new (std::nothrow) _Elem[_Size]())); -} + /** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon + allocation failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + elem.Bar(); + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, + wistd::unique_ptr<_Ty>>::type + make_unique_nothrow(size_t _Size) + { + typedef typename wistd::remove_extent<_Ty>::type _Elem; + return (wistd::unique_ptr<_Ty>(new (std::nothrow) _Elem[_Size]())); + } -template -typename wistd::enable_if::value != 0, void>::type make_unique_nothrow(_Types&&...) = delete; + template + typename wistd::enable_if::value != 0, void>::type make_unique_nothrow(_Types &&...) = delete; #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -/** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation failure. -See the overload of `wil::make_unique_nothrow()` for non-array types for more details. -~~~ -auto foo = wil::make_unique_failfast(fooConstructorParam1, fooConstructorParam2); -foo->Bar(); -~~~ -*/ -template -inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty>>::type make_unique_failfast(_Types&&... _Args) -{ + /** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation + failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_failfast(fooConstructorParam1, fooConstructorParam2); + foo->Bar(); + ~~~ + */ + template + inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty>>::type make_unique_failfast( + _Types &&..._Args) + { #pragma warning(suppress : 28193) // temporary must be inspected (it is within the called function) - return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new (std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)))); -} + return ( + wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new (std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)))); + } -/** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon allocation -failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. -~~~ -const size_t size = 42; -auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object -for (auto& elem : wil::make_range(foos.get(), size)) -{ -elem.Bar(); -} -~~~ -*/ -template -inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty>>::type make_unique_failfast( - size_t _Size) -{ - typedef typename wistd::remove_extent<_Ty>::type _Elem; + /** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon + allocation failure. See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object + for (auto& elem : wil::make_range(foos.get(), size)) + { + elem.Bar(); + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, + wistd::unique_ptr<_Ty>>::type + make_unique_failfast(size_t _Size) + { + typedef typename wistd::remove_extent<_Ty>::type _Elem; #pragma warning(suppress : 28193) // temporary must be inspected (it is within the called function) - return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new (std::nothrow) _Elem[_Size]()))); -} + return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new (std::nothrow) _Elem[_Size]()))); + } -template -typename wistd::enable_if::value != 0, void>::type make_unique_failfast(_Types&&...) = delete; + template + typename wistd::enable_if::value != 0, void>::type make_unique_failfast(_Types &&...) = delete; #endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) #endif // __WIL__NOTHROW_T_DEFINED #if (defined(_WINBASE_) && !defined(__WIL_WINBASE_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_ -namespace details -{ - inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT + namespace details { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h)); - } - - inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h)); - } - - inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h)); - } - - inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr)); - } - - inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h)); - } - - inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN* linkedToken) WI_NOEXCEPT - { - if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE)) + inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken)); + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h)); } - } - enum class PendingCallbackCancellationBehavior - { - Cancel, - Wait, - NoWait, - }; + inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h)); + } - template - struct DestroyThreadPoolWait - { - static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT { - ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr); - ::WaitForThreadpoolWaitCallbacks(threadPoolWait, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolWait(threadPoolWait); + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h)); } - }; - template <> - struct DestroyThreadPoolWait - { - static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT { - ::CloseThreadpoolWait(threadPoolWait); + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr)); } - }; - template - struct DestroyThreadPoolWork - { - static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT { - ::WaitForThreadpoolWorkCallbacks(threadpoolWork, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolWork(threadpoolWork); + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h)); } - }; - template <> - struct DestroyThreadPoolWork - { - static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN *linkedToken) WI_NOEXCEPT { - ::CloseThreadpoolWork(threadpoolWork); - } - }; - - // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<> - struct SystemThreadPoolMethods - { - static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, _In_ DWORD Period, _In_ DWORD WindowLength) WI_NOEXCEPT - { - ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength); - } - static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT - { - ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks); - } - static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT - { - ::CloseThreadpoolTimer(Timer); - } - }; - - // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks, - // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running. - template - struct DestroyThreadPoolTimer - { - static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT - { - threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0); -#pragma warning(suppress : 4127) // conditional expression is constant - if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait) + if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE)) { - threadpool_t::WaitForThreadpoolTimerCallbacks( - threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken)); } - threadpool_t::CloseThreadpoolTimer(threadpoolTimer); } - }; - // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for - // callbacks when destructing. - template - struct DestroyThreadPoolTimer - { - static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT + enum class PendingCallbackCancellationBehavior { - threadpool_t::CloseThreadpoolTimer(threadpoolTimer); - } - }; + Cancel, + Wait, + NoWait, + }; - template - struct DestroyThreadPoolIo - { - static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + template struct DestroyThreadPoolWait { - ::WaitForThreadpoolIoCallbacks(threadpoolIo, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolIo(threadpoolIo); - } - }; + static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + { + ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr); + ::WaitForThreadpoolWaitCallbacks(threadPoolWait, + (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolWait(threadPoolWait); + } + }; - template <> - struct DestroyThreadPoolIo - { - static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + template <> struct DestroyThreadPoolWait { - ::CloseThreadpoolIo(threadpoolIo); - } - }; + static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + { + ::CloseThreadpoolWait(threadPoolWait); + } + }; + + template struct DestroyThreadPoolWork + { + static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + { + ::WaitForThreadpoolWorkCallbacks(threadpoolWork, + (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolWork(threadpoolWork); + } + }; + + template <> struct DestroyThreadPoolWork + { + static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + { + ::CloseThreadpoolWork(threadpoolWork); + } + }; + + // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<> + struct SystemThreadPoolMethods + { + static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, + _In_ DWORD Period, _In_ DWORD WindowLength) WI_NOEXCEPT + { + ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength); + } + static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, + _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT + { + ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks); + } + static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT + { + ::CloseThreadpoolTimer(Timer); + } + }; + + // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks, + // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running. + template + struct DestroyThreadPoolTimer + { + static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT + { + threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0); +#pragma warning(suppress : 4127) // conditional expression is constant + if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait) + { + threadpool_t::WaitForThreadpoolTimerCallbacks( + threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + } + threadpool_t::CloseThreadpoolTimer(threadpoolTimer); + } + }; + + // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for + // callbacks when destructing. + template + struct DestroyThreadPoolTimer + { + static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT + { + threadpool_t::CloseThreadpoolTimer(threadpoolTimer); + } + }; + + template struct DestroyThreadPoolIo + { + static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + { + ::WaitForThreadpoolIoCallbacks(threadpoolIo, + (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolIo(threadpoolIo); + } + }; + + template <> struct DestroyThreadPoolIo + { + static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + { + ::CloseThreadpoolIo(threadpoolIo); + } + }; + + template + struct handle_invalid_resource_policy + : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT + { + return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); + } + }; + + template + struct handle_null_resource_policy : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT + { + return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); + } + }; + + template + struct handle_null_only_resource_policy : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT + { + return (ptr != nullptr); + } + }; + + typedef resource_policy + handle_resource_policy; + } // namespace details + /// @endcond template - struct handle_invalid_resource_policy - : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT - { - return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); - } - }; + using unique_any_handle_invalid = + unique_any_t>>; template - struct handle_null_resource_policy : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT - { - return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); - } - }; + using unique_any_handle_null = + unique_any_t>>; template - struct handle_null_only_resource_policy : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT - { - return (ptr != nullptr); - } - }; + using unique_any_handle_null_only = + unique_any_t>>; - typedef resource_policy handle_resource_policy; -} // namespace details -/// @endcond + typedef unique_any_handle_invalid unique_hfile; + typedef unique_any_handle_null unique_handle; + typedef unique_any_handle_invalid unique_hfind; + typedef unique_any unique_hmodule; + typedef unique_any_handle_null_only unique_process_handle; -template -using unique_any_handle_invalid = - unique_any_t>>; - -template -using unique_any_handle_null = unique_any_t>>; - -template -using unique_any_handle_null_only = - unique_any_t>>; - -typedef unique_any_handle_invalid unique_hfile; -typedef unique_any_handle_null unique_handle; -typedef unique_any_handle_invalid unique_hfind; -typedef unique_any unique_hmodule; -typedef unique_any_handle_null_only unique_process_handle; - -typedef unique_struct unique_token_linked_token; + typedef unique_struct + unique_token_linked_token; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -typedef unique_any unique_sid; -typedef unique_any_handle_null_only unique_boundary_descriptor; + typedef unique_any unique_sid; + typedef unique_any_handle_null_only + unique_boundary_descriptor; -/// @cond -namespace details -{ - template - inline void __stdcall ClosePrivateNamespaceHelper(HANDLE h) WI_NOEXCEPT + /// @cond + namespace details { - ::ClosePrivateNamespace(h, flags); - } -} // namespace details -/// @endcond + template inline void __stdcall ClosePrivateNamespaceHelper(HANDLE h) WI_NOEXCEPT + { + ::ClosePrivateNamespace(h, flags); + } + } // namespace details + /// @endcond -template -using unique_private_namespace = - unique_any_handle_null_only>; + template + using unique_private_namespace = unique_any_handle_null_only>; -using unique_private_namespace_close = unique_private_namespace<>; -using unique_private_namespace_destroy = unique_private_namespace; + using unique_private_namespace_close = unique_private_namespace<>; + using unique_private_namespace_destroy = unique_private_namespace; #endif -using unique_tool_help_snapshot = unique_hfile; + using unique_tool_help_snapshot = unique_hfile; -typedef unique_any::Destroy> unique_threadpool_wait; -typedef unique_any::Destroy> unique_threadpool_wait_nocancel; -typedef unique_any::Destroy> unique_threadpool_wait_nowait; -typedef unique_any::Destroy> unique_threadpool_work; -typedef unique_any::Destroy> unique_threadpool_work_nocancel; -typedef unique_any::Destroy> unique_threadpool_work_nowait; -typedef unique_any::Destroy> - unique_threadpool_timer; -typedef unique_any::Destroy> - unique_threadpool_timer_nocancel; -typedef unique_any::Destroy> - unique_threadpool_timer_nowait; -typedef unique_any::Destroy> unique_threadpool_io; -typedef unique_any::Destroy> unique_threadpool_io_nocancel; -typedef unique_any::Destroy> unique_threadpool_io_nowait; + typedef unique_any::Destroy> + unique_threadpool_wait; + typedef unique_any::Destroy> + unique_threadpool_wait_nocancel; + typedef unique_any::Destroy> + unique_threadpool_wait_nowait; + typedef unique_any::Destroy> + unique_threadpool_work; + typedef unique_any::Destroy> + unique_threadpool_work_nocancel; + typedef unique_any::Destroy> + unique_threadpool_work_nowait; + typedef unique_any::Destroy> + unique_threadpool_timer; + typedef unique_any::Destroy> + unique_threadpool_timer_nocancel; + typedef unique_any::Destroy> + unique_threadpool_timer_nowait; + typedef unique_any::Destroy> + unique_threadpool_io; + typedef unique_any::Destroy> + unique_threadpool_io_nocancel; + typedef unique_any::Destroy> + unique_threadpool_io_nowait; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -typedef unique_any_handle_invalid unique_hfind_change; + typedef unique_any_handle_invalid + unique_hfind_change; #endif -typedef unique_any event_set_scope_exit; -typedef unique_any event_reset_scope_exit; - -// Guarantees a SetEvent on the given event handle when the returned object goes out of scope -// Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method -WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT -{ - __FAIL_FAST_ASSERT__(hEvent != nullptr); - return event_set_scope_exit(hEvent); -} - -// Guarantees a ResetEvent on the given event handle when the returned object goes out of scope -// Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method -WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT -{ - __FAIL_FAST_ASSERT__(hEvent != nullptr); - return event_reset_scope_exit(hEvent); -} - -// Checks to see if the given *manual reset* event is currently signaled. The event must not be an auto-reset event. -// Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread -inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT -{ - auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE); - // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset - // from a thread other than the polling thread (use event_wait directly for those cases). - __FAIL_FAST_ASSERT__( - (status == WAIT_TIMEOUT) || ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE)))); - return (status == WAIT_OBJECT_0); -} - -// Waits on the given handle for the specified duration -inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT -{ - DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, bAlertable); - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); - return (status == WAIT_OBJECT_0); -} - -enum class EventOptions -{ - None = 0x0, - ManualReset = 0x1, - Signaled = 0x2 -}; -DEFINE_ENUM_FLAG_OPERATORS(EventOptions); - -template -class event_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit event_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) - { - } - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructor to create an unnamed event - event_t(EventOptions options) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(options); - } - - void ResetEvent() const WI_NOEXCEPT - { - details::ResetEvent(storage_t::get()); - } - - void SetEvent() const WI_NOEXCEPT - { - details::SetEvent(storage_t::get()); - } + typedef unique_any + event_set_scope_exit; + typedef unique_any + event_reset_scope_exit; // Guarantees a SetEvent on the given event handle when the returned object goes out of scope - // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT + // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() + // method + WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT { - return wil::SetEvent_scope_exit(storage_t::get()); + __FAIL_FAST_ASSERT__(hEvent != nullptr); + return event_set_scope_exit(hEvent); } // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope - // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT + // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() + // method + WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT { - return wil::ResetEvent_scope_exit(storage_t::get()); + __FAIL_FAST_ASSERT__(hEvent != nullptr); + return event_reset_scope_exit(hEvent); } - // Checks if a *manual reset* event is currently signaled. The event must not be an auto-reset event. - // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT + // Checks to see if the given *manual reset* event is currently signaled. The event must not be an auto-reset + // event. Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread + inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT { - return wil::event_is_signaled(storage_t::get()); + auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE); + // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset + // from a thread other than the polling thread (use event_wait directly for those cases). + __FAIL_FAST_ASSERT__( + (status == WAIT_TIMEOUT) || + ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE)))); + return (status == WAIT_OBJECT_0); } - // Basic WaitForSingleObject on the event handle with the given timeout - bool wait(DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT + // Waits on the given handle for the specified duration + inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT { - return wil::handle_wait(storage_t::get(), dwMilliseconds, bAlertable); + DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, bAlertable); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || + (bAlertable && (status == WAIT_IO_COMPLETION))); + return (status == WAIT_OBJECT_0); } - // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, _Out_opt_ bool* alreadyExists = nullptr) + enum class EventOptions { - auto handle = ::CreateEventExW( - securityAttributes, - name, - (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | - (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), - EVENT_ALL_ACCESS); - if (!handle) + None = 0x0, + ManualReset = 0x1, + Signaled = 0x2 + }; + DEFINE_ENUM_FLAG_OPERATORS(EventOptions); + + template class event_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit event_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) { - assign_to_opt_param(alreadyExists, false); - return false; } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event - result create( - EventOptions options = EventOptions::None, - PCWSTR name = nullptr, - _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, - _Out_opt_ bool* alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse(try_create(options, name, securityAttributes, alreadyExists)); - } + // HRESULT or void error handling... + typedef typename err_policy::result result; - // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenEventW(desiredAccess, inheritHandle, name); - if (handle == nullptr) + // Exception-based constructor to create an unnamed event + event_t(EventOptions options) { - return false; + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(options); } - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } -}; + void ResetEvent() const WI_NOEXCEPT + { + details::ResetEvent(storage_t::get()); + } -typedef unique_any_t, err_returncode_policy>> unique_event_nothrow; -typedef unique_any_t, err_failfast_policy>> unique_event_failfast; + void SetEvent() const WI_NOEXCEPT + { + details::SetEvent(storage_t::get()); + } + + // Guarantees a SetEvent on the given event handle when the returned object goes out of scope + // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() + // method + WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT + { + return wil::SetEvent_scope_exit(storage_t::get()); + } + + // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope + // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the + // release() method + WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT + { + return wil::ResetEvent_scope_exit(storage_t::get()); + } + + // Checks if a *manual reset* event is currently signaled. The event must not be an auto-reset event. + // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread + WI_NODISCARD bool is_signaled() const WI_NOEXCEPT + { + return wil::event_is_signaled(storage_t::get()); + } + + // Basic WaitForSingleObject on the event handle with the given timeout + bool wait(DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT + { + return wil::handle_wait(storage_t::get(), dwMilliseconds, bAlertable); + } + + // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, + _Out_opt_ bool *alreadyExists = nullptr) + { + auto handle = + ::CreateEventExW(securityAttributes, name, + (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | + (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), + EVENT_ALL_ACCESS); + if (!handle) + { + assign_to_opt_param(alreadyExists, false); + return false; + } + assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event + result create(EventOptions options = EventOptions::None, PCWSTR name = nullptr, + _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, + _Out_opt_ bool *alreadyExists = nullptr) + { + return err_policy::LastErrorIfFalse(try_create(options, name, securityAttributes, alreadyExists)); + } + + // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, + bool inheritHandle = false) + { + auto handle = ::OpenEventW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, + bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); + } + }; + + typedef unique_any_t, err_returncode_policy>> + unique_event_nothrow; + typedef unique_any_t, err_failfast_policy>> + unique_event_failfast; #ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_event; + typedef unique_any_t, err_exception_policy>> + unique_event; #endif #ifndef WIL_NO_SLIM_EVENT -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ ((_WIN32_WINNT >= _WIN32_WINNT_WIN8) || (__WIL_RESOURCE_ENABLE_QUIRKS && (_WIN32_WINNT >= _WIN32_WINNT_WIN7))) -enum class SlimEventType -{ - AutoReset, - ManualReset, -}; - -/** A lean and mean event class. -This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object. - -The two variants of this class are: -- `wil::slim_event_auto_reset` -- `wil::slim_event_manual_reset` - -In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`. - -Some key differences to `wil::unique_event` include: -- There is no 'create()' function, as initialization occurs in the constructor and can't fail. -- The move functions have been deleted. -- For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.) -- The `ResetEvent()` function returns the previous state of the event. -- To create a manual reset event, use `wil::slim_event_manual_reset'. -~~~~ -wil::slim_event finished; -std::thread doStuff([&finished] () { - Sleep(10); - finished.SetEvent(); -}); -finished.wait(); - -std::shared_ptr CreateSharedEvent(bool startSignaled) -{ - return std::make_shared(startSignaled); -} -~~~~ */ -template -class slim_event_t -{ -public: - slim_event_t() WI_NOEXCEPT = default; - - slim_event_t(bool isSignaled) WI_NOEXCEPT : m_isSignaled(isSignaled ? TRUE : FALSE) + enum class SlimEventType { + AutoReset, + ManualReset, + }; + + /** A lean and mean event class. + This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object. + + The two variants of this class are: + - `wil::slim_event_auto_reset` + - `wil::slim_event_manual_reset` + + In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`. + + Some key differences to `wil::unique_event` include: + - There is no 'create()' function, as initialization occurs in the constructor and can't fail. + - The move functions have been deleted. + - For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.) + - The `ResetEvent()` function returns the previous state of the event. + - To create a manual reset event, use `wil::slim_event_manual_reset'. + ~~~~ + wil::slim_event finished; + std::thread doStuff([&finished] () { + Sleep(10); + finished.SetEvent(); + }); + finished.wait(); + + std::shared_ptr CreateSharedEvent(bool startSignaled) + { + return std::make_shared(startSignaled); } - - // Cannot change memory location. - slim_event_t(const slim_event_t&) = delete; - slim_event_t(slim_event_t&&) = delete; - slim_event_t& operator=(const slim_event_t&) = delete; - slim_event_t& operator=(slim_event_t&&) = delete; - - // Returns the previous state of the event. - bool ResetEvent() WI_NOEXCEPT + ~~~~ */ + template class slim_event_t { - return !!InterlockedExchange(&m_isSignaled, FALSE); - } + public: + slim_event_t() WI_NOEXCEPT = default; - void SetEvent() WI_NOEXCEPT - { - // FYI: 'WakeByAddress*' invokes a full memory barrier. - WriteRelease(&m_isSignaled, TRUE); + slim_event_t(bool isSignaled) WI_NOEXCEPT : m_isSignaled(isSignaled ? TRUE : FALSE) + { + } + + // Cannot change memory location. + slim_event_t(const slim_event_t &) = delete; + slim_event_t(slim_event_t &&) = delete; + slim_event_t &operator=(const slim_event_t &) = delete; + slim_event_t &operator=(slim_event_t &&) = delete; + + // Returns the previous state of the event. + bool ResetEvent() WI_NOEXCEPT + { + return !!InterlockedExchange(&m_isSignaled, FALSE); + } + + void SetEvent() WI_NOEXCEPT + { + // FYI: 'WakeByAddress*' invokes a full memory barrier. + WriteRelease(&m_isSignaled, TRUE); #pragma warning(suppress : 4127) // conditional expression is constant - if (Type == SlimEventType::AutoReset) - { - WakeByAddressSingle(&m_isSignaled); - } - else - { - WakeByAddressAll(&m_isSignaled); - } - } - - // Checks if the event is currently signaled. - // Note: Unlike Win32 auto-reset event objects, this will not reset the event. - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT - { - return !!ReadAcquire(&m_isSignaled); - } - - bool wait(DWORD timeoutMilliseconds) WI_NOEXCEPT - { - if (timeoutMilliseconds == 0) - { - return TryAcquireEvent(); - } - else if (timeoutMilliseconds == INFINITE) - { - return wait(); - } - - UINT64 startTime{}; - QueryUnbiasedInterruptTime(&startTime); - - UINT64 elapsedTimeMilliseconds = 0; - - while (!TryAcquireEvent()) - { - if (elapsedTimeMilliseconds >= timeoutMilliseconds) + if (Type == SlimEventType::AutoReset) { - return false; + WakeByAddressSingle(&m_isSignaled); } - - DWORD newTimeout = static_cast(timeoutMilliseconds - elapsedTimeMilliseconds); - - if (!WaitForSignal(newTimeout)) + else { - return false; - } - - UINT64 currTime; - QueryUnbiasedInterruptTime(&currTime); - - elapsedTimeMilliseconds = (currTime - startTime) / static_cast(10 * 1000); - } - - return true; - } - - bool wait() WI_NOEXCEPT - { - while (!TryAcquireEvent()) - { - if (!WaitForSignal(INFINITE)) - { - return false; + WakeByAddressAll(&m_isSignaled); } } - return true; - } + // Checks if the event is currently signaled. + // Note: Unlike Win32 auto-reset event objects, this will not reset the event. + WI_NODISCARD bool is_signaled() const WI_NOEXCEPT + { + return !!ReadAcquire(&m_isSignaled); + } -private: - bool TryAcquireEvent() WI_NOEXCEPT - { + bool wait(DWORD timeoutMilliseconds) WI_NOEXCEPT + { + if (timeoutMilliseconds == 0) + { + return TryAcquireEvent(); + } + else if (timeoutMilliseconds == INFINITE) + { + return wait(); + } + + UINT64 startTime{}; + QueryUnbiasedInterruptTime(&startTime); + + UINT64 elapsedTimeMilliseconds = 0; + + while (!TryAcquireEvent()) + { + if (elapsedTimeMilliseconds >= timeoutMilliseconds) + { + return false; + } + + DWORD newTimeout = static_cast(timeoutMilliseconds - elapsedTimeMilliseconds); + + if (!WaitForSignal(newTimeout)) + { + return false; + } + + UINT64 currTime; + QueryUnbiasedInterruptTime(&currTime); + + elapsedTimeMilliseconds = (currTime - startTime) / static_cast(10 * 1000); + } + + return true; + } + + bool wait() WI_NOEXCEPT + { + while (!TryAcquireEvent()) + { + if (!WaitForSignal(INFINITE)) + { + return false; + } + } + + return true; + } + + private: + bool TryAcquireEvent() WI_NOEXCEPT + { #pragma warning(suppress : 4127) // conditional expression is constant - if (Type == SlimEventType::AutoReset) - { - return ResetEvent(); + if (Type == SlimEventType::AutoReset) + { + return ResetEvent(); + } + else + { + return is_signaled(); + } } - else + + bool WaitForSignal(DWORD timeoutMilliseconds) WI_NOEXCEPT { - return is_signaled(); + LONG falseValue = FALSE; + BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMilliseconds); + __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT); + return !!waitResult; } - } - bool WaitForSignal(DWORD timeoutMilliseconds) WI_NOEXCEPT - { - LONG falseValue = FALSE; - BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMilliseconds); - __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT); - return !!waitResult; - } + LONG m_isSignaled = FALSE; + }; - LONG m_isSignaled = FALSE; -}; + /** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. + * returns true). */ + using slim_event_auto_reset = slim_event_t; -/** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. returns true). */ -using slim_event_auto_reset = slim_event_t; + /** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */ + using slim_event_manual_reset = slim_event_t; -/** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */ -using slim_event_manual_reset = slim_event_t; - -/** An alias for `wil::slim_event_auto_reset`. */ -using slim_event = slim_event_auto_reset; + /** An alias for `wil::slim_event_auto_reset`. */ + using slim_event = slim_event_auto_reset; #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8) #endif // WIL_NO_SLIM_EVENT -typedef unique_any mutex_release_scope_exit; + typedef unique_any + mutex_release_scope_exit; -WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT -{ - __FAIL_FAST_ASSERT__(hMutex != nullptr); - return mutex_release_scope_exit(hMutex); -} - -// For efficiency, avoid using mutexes when an srwlock or condition variable will do. -template -class mutex_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit mutex_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) + WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT { + __FAIL_FAST_ASSERT__(hMutex != nullptr); + return mutex_release_scope_exit(hMutex); } - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name) - mutex_t(_In_opt_ PCWSTR name) + // For efficiency, avoid using mutexes when an srwlock or condition variable will do. + template class mutex_t : public storage_t { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(name); - } - - void ReleaseMutex() const WI_NOEXCEPT - { - details::ReleaseMutex(storage_t::get()); - } - - WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT - { - return wil::ReleaseMutex_scope_exit(storage_t::get()); - } - - WI_NODISCARD mutex_release_scope_exit - acquire(_Out_opt_ DWORD* pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT - { - auto handle = storage_t::get(); - DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); - assign_to_opt_param(pStatus, status); - __FAIL_FAST_ASSERT__( - (status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || - (bAlertable && (status == WAIT_IO_COMPLETION))); - return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle : nullptr); - } - - // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create( - _In_opt_ PCWSTR name, - DWORD dwFlags = 0, - DWORD desiredAccess = MUTEX_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, - _Out_opt_ bool* alreadyExists = nullptr) - { - auto handle = ::CreateMutexExW(mutexAttributes, name, dwFlags, desiredAccess); - if (handle == nullptr) + public: + // forward all base class constructors... + template + explicit mutex_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) { - assign_to_opt_param(alreadyExists, false); - return false; } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex - result create( - _In_opt_ PCWSTR name = nullptr, - DWORD dwFlags = 0, - DWORD desiredAccess = MUTEX_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, - _Out_opt_ bool* alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse(try_create(name, dwFlags, desiredAccess, mutexAttributes, alreadyExists)); - } + // HRESULT or void error handling... + typedef typename err_policy::result result; - // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name); - if (handle == nullptr) + // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name) + mutex_t(_In_opt_ PCWSTR name) { - return false; + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(name); } - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } -}; - -typedef unique_any_t, err_returncode_policy>> unique_mutex_nothrow; -typedef unique_any_t, err_failfast_policy>> unique_mutex_failfast; -#ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_mutex; -#endif - -typedef unique_any semaphore_release_scope_exit; - -WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT -{ - __FAIL_FAST_ASSERT__(hSemaphore != nullptr); - return semaphore_release_scope_exit(hSemaphore); -} - -template -class semaphore_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit semaphore_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) - { - } - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit conversions will make it through the - // forwarding constructor. This constructor, for example, uses 'int' instead of 'LONG' as the count to ease that particular issue (const numbers are int by default). - explicit semaphore_t( - int initialCount, - int maximumCount, - _In_opt_ PCWSTR name = nullptr, - DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes); - } - - void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long* pnPreviousCount = nullptr) WI_NOEXCEPT - { - long nPreviousCount = 0; - __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount)); - assign_to_opt_param(pnPreviousCount, nPreviousCount); - } - - WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT - { - return wil::ReleaseSemaphore_scope_exit(storage_t::get()); - } - - WI_NODISCARD semaphore_release_scope_exit - acquire(_Out_opt_ DWORD* pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT - { - auto handle = storage_t::get(); - DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); - assign_to_opt_param(pStatus, status); - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); - return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr); - } - - // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create( - LONG lInitialCount, - LONG lMaximumCount, - _In_opt_ PCWSTR name, - DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, - _Out_opt_ bool* alreadyExists = nullptr) - { - auto handle = ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess); - if (handle == nullptr) + void ReleaseMutex() const WI_NOEXCEPT { - assign_to_opt_param(alreadyExists, false); - return false; + details::ReleaseMutex(storage_t::get()); } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event - result create( - LONG lInitialCount, - LONG lMaximumCount, - _In_opt_ PCWSTR name = nullptr, - DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, - _Out_opt_ bool* alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse( - try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes, alreadyExists)); - } - - // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name); - if (handle == nullptr) + WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT { - return false; + return wil::ReleaseMutex_scope_exit(storage_t::get()); } - storage_t::reset(handle); - return true; - } - // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } -}; - -typedef unique_any_t, err_returncode_policy>> unique_semaphore_nothrow; -typedef unique_any_t, err_failfast_policy>> unique_semaphore_failfast; -#ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_semaphore; -#endif - -typedef unique_any rwlock_release_exclusive_scope_exit; -typedef unique_any rwlock_release_shared_scope_exit; - -WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK* plock) WI_NOEXCEPT -{ - ::AcquireSRWLockExclusive(plock); - return rwlock_release_exclusive_scope_exit(plock); -} - -WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK* plock) WI_NOEXCEPT -{ - ::AcquireSRWLockShared(plock); - return rwlock_release_shared_scope_exit(plock); -} - -WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK* plock) WI_NOEXCEPT -{ - return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr); -} - -WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK* plock) WI_NOEXCEPT -{ - return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr); -} - -class srwlock -{ -public: - srwlock(const srwlock&) = delete; - srwlock(srwlock&&) = delete; - srwlock& operator=(const srwlock&) = delete; - srwlock& operator=(srwlock&&) = delete; - - srwlock() = default; - - WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT - { - return wil::AcquireSRWLockExclusive(&m_lock); - } - - WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT - { - return wil::TryAcquireSRWLockExclusive(&m_lock); - } - - WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT - { - return wil::AcquireSRWLockShared(&m_lock); - } - - WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT - { - return wil::TryAcquireSRWLockShared(&m_lock); - } - -private: - SRWLOCK m_lock = SRWLOCK_INIT; -}; - -typedef unique_any cs_leave_scope_exit; - -WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION* pcs) WI_NOEXCEPT -{ - ::EnterCriticalSection(pcs); - return cs_leave_scope_exit(pcs); -} - -WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION* pcs) WI_NOEXCEPT -{ - return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr); -} - -// Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute -// being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition. -class critical_section -{ -public: - critical_section(const critical_section&) = delete; - critical_section(critical_section&&) = delete; - critical_section& operator=(const critical_section&) = delete; - critical_section& operator=(critical_section&&) = delete; - - critical_section(ULONG spincount = 0) WI_NOEXCEPT - { - // Initialization will not fail without invalid params... - ::InitializeCriticalSectionEx(&m_cs, spincount, 0); - } - - ~critical_section() WI_NOEXCEPT - { - ::DeleteCriticalSection(&m_cs); - } - - WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT - { - return wil::EnterCriticalSection(&m_cs); - } - - WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT - { - return wil::TryEnterCriticalSection(&m_cs); - } - -private: - CRITICAL_SECTION m_cs; -}; - -class condition_variable -{ -public: - condition_variable(const condition_variable&) = delete; - condition_variable(condition_variable&&) = delete; - condition_variable& operator=(const condition_variable&) = delete; - condition_variable& operator=(condition_variable&&) = delete; - - condition_variable() = default; - - void notify_one() WI_NOEXCEPT - { - ::WakeConditionVariable(&m_cv); - } - - void notify_all() WI_NOEXCEPT - { - ::WakeAllConditionVariable(&m_cv); - } - - void wait(const cs_leave_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - void wait(const rwlock_release_exclusive_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - void wait(const rwlock_release_shared_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - bool wait_for(const cs_leave_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - - bool wait_for(const rwlock_release_exclusive_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - - bool wait_for(const rwlock_release_shared_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - -private: - CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT; -}; - -/// @cond -namespace details -{ - template - struct string_allocator - { - static void* allocate(size_t /*size*/) WI_NOEXCEPT + WI_NODISCARD mutex_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, + DWORD dwMilliseconds = INFINITE, + BOOL bAlertable = FALSE) const WI_NOEXCEPT { - static_assert( - !wistd::is_same::value, - "This type did not provide a string_allocator, add a specialization of string_allocator to support your type."); - return nullptr; + auto handle = storage_t::get(); + DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); + assign_to_opt_param(pStatus, status); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || + (bAlertable && (status == WAIT_IO_COMPLETION))); + return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle + : nullptr); + } + + // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_create(_In_opt_ PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, + _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, + _Out_opt_ bool *alreadyExists = nullptr) + { + auto handle = ::CreateMutexExW(mutexAttributes, name, dwFlags, desiredAccess); + if (handle == nullptr) + { + assign_to_opt_param(alreadyExists, false); + return false; + } + assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex + result create(_In_opt_ PCWSTR name = nullptr, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, + _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, _Out_opt_ bool *alreadyExists = nullptr) + { + return err_policy::LastErrorIfFalse( + try_create(name, dwFlags, desiredAccess, mutexAttributes, alreadyExists)); + } + + // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, + bool inheritHandle = false) + { + auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, + bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); } }; -} // namespace details -/// @endcond -// This string helper does not support the ansi wil string helpers -template -PCWSTR string_get_not_null(const string_type& string) -{ - return string ? string.get() : L""; -} + typedef unique_any_t, err_returncode_policy>> + unique_mutex_nothrow; + typedef unique_any_t, err_failfast_policy>> + unique_mutex_failfast; +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> + unique_mutex; +#endif + + typedef unique_any + semaphore_release_scope_exit; + + WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT__(hSemaphore != nullptr); + return semaphore_release_scope_exit(hSemaphore); + } + + template class semaphore_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit semaphore_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) + { + } + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit + // conversions will make it through the forwarding constructor. This constructor, for example, uses 'int' + // instead of 'LONG' as the count to ease that particular issue (const numbers are int by default). + explicit semaphore_t(int initialCount, int maximumCount, _In_opt_ PCWSTR name = nullptr, + DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, + _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes); + } + + void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long *pnPreviousCount = nullptr) WI_NOEXCEPT + { + long nPreviousCount = 0; + __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount)); + assign_to_opt_param(pnPreviousCount, nPreviousCount); + } + + WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT + { + return wil::ReleaseSemaphore_scope_exit(storage_t::get()); + } + + WI_NODISCARD semaphore_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, + DWORD dwMilliseconds = INFINITE, + BOOL bAlertable = FALSE) WI_NOEXCEPT + { + auto handle = storage_t::get(); + DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); + assign_to_opt_param(pStatus, status); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || + (bAlertable && (status == WAIT_IO_COMPLETION))); + return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr); + } + + // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name, + DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, + _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, + _Out_opt_ bool *alreadyExists = nullptr) + { + auto handle = + ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess); + if (handle == nullptr) + { + assign_to_opt_param(alreadyExists, false); + return false; + } + assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event + result create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name = nullptr, + DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, + _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, + _Out_opt_ bool *alreadyExists = nullptr) + { + return err_policy::LastErrorIfFalse( + try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes, alreadyExists)); + } + + // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with + // return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, + bool inheritHandle = false) + { + auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, + bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); + } + }; + + typedef unique_any_t, err_returncode_policy>> + unique_semaphore_nothrow; + typedef unique_any_t, err_failfast_policy>> + unique_semaphore_failfast; +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> + unique_semaphore; +#endif + + typedef unique_any + rwlock_release_exclusive_scope_exit; + typedef unique_any + rwlock_release_shared_scope_exit; + + WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + ::AcquireSRWLockExclusive(plock); + return rwlock_release_exclusive_scope_exit(plock); + } + + WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + ::AcquireSRWLockShared(plock); + return rwlock_release_shared_scope_exit(plock); + } + + WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) + WI_NOEXCEPT + { + return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr); + } + + WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr); + } + + class srwlock + { + public: + srwlock(const srwlock &) = delete; + srwlock(srwlock &&) = delete; + srwlock &operator=(const srwlock &) = delete; + srwlock &operator=(srwlock &&) = delete; + + srwlock() = default; + + WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT + { + return wil::AcquireSRWLockExclusive(&m_lock); + } + + WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT + { + return wil::TryAcquireSRWLockExclusive(&m_lock); + } + + WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT + { + return wil::AcquireSRWLockShared(&m_lock); + } + + WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT + { + return wil::TryAcquireSRWLockShared(&m_lock); + } + + private: + SRWLOCK m_lock = SRWLOCK_INIT; + }; + + typedef unique_any + cs_leave_scope_exit; + + WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT + { + ::EnterCriticalSection(pcs); + return cs_leave_scope_exit(pcs); + } + + WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT + { + return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr); + } + + // Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute + // being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition. + class critical_section + { + public: + critical_section(const critical_section &) = delete; + critical_section(critical_section &&) = delete; + critical_section &operator=(const critical_section &) = delete; + critical_section &operator=(critical_section &&) = delete; + + critical_section(ULONG spincount = 0) WI_NOEXCEPT + { + // Initialization will not fail without invalid params... + ::InitializeCriticalSectionEx(&m_cs, spincount, 0); + } + + ~critical_section() WI_NOEXCEPT + { + ::DeleteCriticalSection(&m_cs); + } + + WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT + { + return wil::EnterCriticalSection(&m_cs); + } + + WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT + { + return wil::TryEnterCriticalSection(&m_cs); + } + + private: + CRITICAL_SECTION m_cs; + }; + + class condition_variable + { + public: + condition_variable(const condition_variable &) = delete; + condition_variable(condition_variable &&) = delete; + condition_variable &operator=(const condition_variable &) = delete; + condition_variable &operator=(condition_variable &&) = delete; + + condition_variable() = default; + + void notify_one() WI_NOEXCEPT + { + ::WakeConditionVariable(&m_cv); + } + + void notify_all() WI_NOEXCEPT + { + ::WakeAllConditionVariable(&m_cv); + } + + void wait(const cs_leave_scope_exit &lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + void wait(const rwlock_release_exclusive_scope_exit &lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + void wait(const rwlock_release_shared_scope_exit &lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + bool wait_for(const cs_leave_scope_exit &lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + bool wait_for(const rwlock_release_exclusive_scope_exit &lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + bool wait_for(const rwlock_release_shared_scope_exit &lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = + !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + private: + CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT; + }; + + /// @cond + namespace details + { + template struct string_allocator + { + static void *allocate(size_t /*size*/) WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, + "This type did not provide a string_allocator, add a specialization of string_allocator " + "to support your type."); + return nullptr; + } + }; + } // namespace details + /// @endcond + + // This string helper does not support the ansi wil string helpers + template PCWSTR string_get_not_null(const string_type &string) + { + return string ? string.get() : L""; + } #ifndef MAKE_UNIQUE_STRING_MAX_CCH #define MAKE_UNIQUE_STRING_MAX_CCH 2147483647 // max buffer size, in characters, that we support (same as INT_MAX) #endif -/** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on failure. -Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory allocation contract -that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, LocalAlloc/LocalFree, -GlobalAlloc/GlobalFree, etc.). -~~~ -auto str = wil::make_unique_string_nothrow(L"a string of words", 8); -RETURN_IF_NULL_ALLOC(str); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + /** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on + failure. Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory + allocation contract that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, + LocalAlloc/LocalFree, GlobalAlloc/GlobalFree, etc.). + ~~~ + auto str = wil::make_unique_string_nothrow(L"a string of words", 8); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -auto str = wil::make_unique_string_nothrow(L"a string"); -RETURN_IF_NULL_ALLOC(str); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + auto str = wil::make_unique_string_nothrow(L"a string"); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -NOTE: If source is not null terminated, then length MUST be equal to or less than the size - of the buffer pointed to by source. -~~~ -*/ -template -string_type make_unique_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - // guard against invalid parameters (null source with -1 length) - FAIL_FAST_IF(!source && (length == static_cast(-1))); - - // When the source string exists, calculate the number of characters to copy up to either - // 1) the length that is given - // 2) the length of the source string. When the source does not exist, use the given length - // for calculating both the size of allocated buffer and the number of characters to copy. - size_t lengthToCopy = length; - if (source) - { - size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH; - PCWSTR endOfSource = source; - while (maxLength && (*endOfSource != L'\0')) - { - endOfSource++; - maxLength--; - } - lengthToCopy = endOfSource - source; - } - - if (length == static_cast(-1)) - { - length = lengthToCopy; - } - const size_t allocatedBytes = (length + 1) * sizeof(*source); - auto result = static_cast(details::string_allocator::allocate(allocatedBytes)); - - if (result) - { - if (source) - { - const size_t bytesToCopy = lengthToCopy * sizeof(*source); - memcpy_s(result, allocatedBytes, source, bytesToCopy); - result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated - } - else - { - *result = L'\0'; // ensure null terminated in the "reserve space" use case. - } - result[length] = L'\0'; // ensure the final char of the buffer is zero terminated - } - return string_type(result); -} -#ifndef WIL_NO_ANSI_STRINGS -template -string_type make_unique_ansistring_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - if (length == static_cast(-1)) + NOTE: If source is not null terminated, then length MUST be equal to or less than the size + of the buffer pointed to by source. + ~~~ + */ + template + string_type make_unique_string_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t *source, + size_t length = static_cast(-1)) WI_NOEXCEPT { // guard against invalid parameters (null source with -1 length) - FAIL_FAST_IF(!source); - length = strlen(source); - } - const size_t cb = (length + 1) * sizeof(*source); - auto result = static_cast(details::string_allocator::allocate(cb)); - if (result) - { + FAIL_FAST_IF(!source && (length == static_cast(-1))); + + // When the source string exists, calculate the number of characters to copy up to either + // 1) the length that is given + // 2) the length of the source string. When the source does not exist, use the given length + // for calculating both the size of allocated buffer and the number of characters to copy. + size_t lengthToCopy = length; if (source) { - memcpy_s(result, cb, source, cb - sizeof(*source)); + size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH; + PCWSTR endOfSource = source; + while (maxLength && (*endOfSource != L'\0')) + { + endOfSource++; + maxLength--; + } + lengthToCopy = endOfSource - source; } - else + + if (length == static_cast(-1)) { - *result = '\0'; // ensure null terminated in the "reserve space" use case. + length = lengthToCopy; } - result[length] = '\0'; // ensure zero terminated + const size_t allocatedBytes = (length + 1) * sizeof(*source); + auto result = static_cast(details::string_allocator::allocate(allocatedBytes)); + + if (result) + { + if (source) + { + const size_t bytesToCopy = lengthToCopy * sizeof(*source); + memcpy_s(result, allocatedBytes, source, bytesToCopy); + result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated + } + else + { + *result = L'\0'; // ensure null terminated in the "reserve space" use case. + } + result[length] = L'\0'; // ensure the final char of the buffer is zero terminated + } + return string_type(result); + } +#ifndef WIL_NO_ANSI_STRINGS + template + string_type make_unique_ansistring_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + if (length == static_cast(-1)) + { + // guard against invalid parameters (null source with -1 length) + FAIL_FAST_IF(!source); + length = strlen(source); + } + const size_t cb = (length + 1) * sizeof(*source); + auto result = static_cast(details::string_allocator::allocate(cb)); + if (result) + { + if (source) + { + memcpy_s(result, cb, source, cb - sizeof(*source)); + } + else + { + *result = '\0'; // ensure null terminated in the "reserve space" use case. + } + result[length] = '\0'; // ensure zero terminated + } + return string_type(result); } - return string_type(result); -} #endif // WIL_NO_ANSI_STRINGS -/** Copies a given string into memory allocated with a specified allocator that will fail fast on failure. -The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. -*/ -template -string_type make_unique_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - auto result(make_unique_string_nothrow(source, length)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Copies a given string into memory allocated with a specified allocator that will fail fast on failure. + The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. + */ + template + string_type make_unique_string_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + auto result(make_unique_string_nothrow(source, length)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #ifndef WIL_NO_ANSI_STRINGS -template -string_type make_unique_ansistring_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - auto result(make_unique_ansistring_nothrow(source, length)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + template + string_type make_unique_ansistring_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + auto result(make_unique_ansistring_nothrow(source, length)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_NO_ANSI_STRINGS #ifdef WIL_ENABLE_EXCEPTIONS -/** Copies a given string into memory allocated with a specified allocator that will throw on failure. -The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. -*/ -template -string_type make_unique_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) -{ - auto result(make_unique_string_nothrow(source, length)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Copies a given string into memory allocated with a specified allocator that will throw on failure. + The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. + */ + template + string_type make_unique_string(_When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) + { + auto result(make_unique_string_nothrow(source, length)); + THROW_IF_NULL_ALLOC(result); + return result; + } #ifndef WIL_NO_ANSI_STRINGS -template -string_type make_unique_ansistring( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) -{ - auto result(make_unique_ansistring_nothrow(source, length)); - THROW_IF_NULL_ALLOC(result); - return result; -} + template + string_type make_unique_ansistring(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, + size_t length = static_cast(-1)) + { + auto result(make_unique_ansistring_nothrow(source, length)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_NO_ANSI_STRINGS #endif // WIL_ENABLE_EXCEPTIONS -/// @cond -namespace details -{ - // string_maker abstracts creating a string for common string types. This form supports the - // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring - // are found in wil/winrt.h and wil/stl.h. - // This design supports creating the string in a single step or using two phase construction. - - template - struct string_maker + /// @cond + namespace details { - HRESULT make( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, - size_t length) + // string_maker abstracts creating a string for common string types. This form supports the + // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring + // are found in wil/winrt.h and wil/stl.h. + // This design supports creating the string in a single step or using two phase construction. + + template struct string_maker { - m_value = make_unique_string_nothrow(source, length); - return m_value ? S_OK : E_OUTOFMEMORY; + HRESULT make(_When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t *source, + size_t length) + { + m_value = make_unique_string_nothrow(source, length); + return m_value ? S_OK : E_OUTOFMEMORY; + } + + wchar_t *buffer() + { + WI_ASSERT(m_value.get()); + return m_value.get(); + } + + // By default, assume string_type is a null-terminated string and therefore does not require trimming. + HRESULT trim_at_existing_null(size_t /* length */) + { + return S_OK; + } + + string_type release() + { + return wistd::move(m_value); + } + + // Utility to abstract access to the null terminated m_value of all string types. + static PCWSTR get(const string_type &value) + { + return value.get(); + } + + private: + string_type m_value; // a wil::unique_xxx_string type. + }; + + struct SecureZeroData + { + void *pointer; + size_t sizeBytes; + SecureZeroData(void *pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT + { + pointer = pointer_; + sizeBytes = sizeBytes_; + } + WI_NODISCARD operator void *() const WI_NOEXCEPT + { + return pointer; + } + static void Close(SecureZeroData data) WI_NOEXCEPT + { + ::SecureZeroMemory(data.pointer, data.sizeBytes); + } + }; + } // namespace details + /// @endcond + + typedef unique_any + secure_zero_memory_scope_exit; + + WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit( + _In_reads_bytes_(sizeBytes) void *pSource, size_t sizeBytes) + { + return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes)); + } + + WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString) + { + return SecureZeroMemory_scope_exit(static_cast(initializedString), + wcslen(initializedString) * sizeof(initializedString[0])); + } + + /// @cond + namespace details + { + inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void *p) + { + ::HeapFree(::GetProcessHeap(), 0, p); } - wchar_t* buffer() + struct heap_allocator { - WI_ASSERT(m_value.get()); - return m_value.get(); - } + static _Ret_opt_bytecap_(size) void *allocate(size_t size) WI_NOEXCEPT + { + return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); + } + }; + } // namespace details + /// @endcond - // By default, assume string_type is a null-terminated string and therefore does not require trimming. - HRESULT trim_at_existing_null(size_t /* length */) + struct process_heap_deleter + { + template void operator()(_Pre_valid_ _Frees_ptr_ T *p) const { - return S_OK; + details::FreeProcessHeap(p); } - - string_type release() - { - return wistd::move(m_value); - } - - // Utility to abstract access to the null terminated m_value of all string types. - static PCWSTR get(const string_type& value) - { - return value.get(); - } - - private: - string_type m_value; // a wil::unique_xxx_string type. }; - struct SecureZeroData + struct virtualalloc_deleter { - void* pointer; - size_t sizeBytes; - SecureZeroData(void* pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT + template void operator()(_Pre_valid_ _Frees_ptr_ T *p) const { - pointer = pointer_; - sizeBytes = sizeBytes_; - } - WI_NODISCARD operator void*() const WI_NOEXCEPT - { - return pointer; - } - static void Close(SecureZeroData data) WI_NOEXCEPT - { - ::SecureZeroMemory(data.pointer, data.sizeBytes); + ::VirtualFree(p, 0, MEM_RELEASE); } }; -} // namespace details -/// @endcond -typedef unique_any secure_zero_memory_scope_exit; - -WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_reads_bytes_(sizeBytes) void* pSource, size_t sizeBytes) -{ - return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes)); -} - -WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString) -{ - return SecureZeroMemory_scope_exit(static_cast(initializedString), wcslen(initializedString) * sizeof(initializedString[0])); -} - -/// @cond -namespace details -{ - inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void* p) + struct mapview_deleter { - ::HeapFree(::GetProcessHeap(), 0, p); - } - - struct heap_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + template void operator()(_Pre_valid_ _Frees_ptr_ T *p) const { - return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); + ::UnmapViewOfFile(p); } }; -} // namespace details -/// @endcond -struct process_heap_deleter -{ - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - details::FreeProcessHeap(p); - } -}; + /** Manages a typed pointer allocated with VirtualAlloc + A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE). + */ + template + using unique_virtualalloc_ptr = + wistd::unique_ptr, virtualalloc_deleter>; -struct virtualalloc_deleter -{ - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - ::VirtualFree(p, 0, MEM_RELEASE); - } -}; - -struct mapview_deleter -{ - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - ::UnmapViewOfFile(p); - } -}; - -/** Manages a typed pointer allocated with VirtualAlloc -A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE). -*/ -template -using unique_virtualalloc_ptr = wistd::unique_ptr, virtualalloc_deleter>; - -/** Manages a typed pointer allocated with MapViewOfFile -A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p). -*/ -template -using unique_mapview_ptr = wistd::unique_ptr, mapview_deleter>; + /** Manages a typed pointer allocated with MapViewOfFile + A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p). + */ + template + using unique_mapview_ptr = wistd::unique_ptr, mapview_deleter>; #endif // __WIL_WINBASE_ -#if (defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED)) || defined(WIL_DOXYGEN) +#if (defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_NOTHROW_T_DEFINED -/// @endcond + /// @endcond -// unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast -// -// Clients must include or to enable use of this class as it uses new(std::nothrow). -// This is to avoid the dependency on those headers that some clients can't tolerate. -// -// These classes makes it easy to execute a provided function when an event -// is signaled. It will create the event handle for you, take ownership of one -// or duplicate a handle provided. It supports the ability to signal the -// event using SetEvent() and SetEvent_scope_exit(); -// -// This can be used to support producer-consumer pattern -// where a producer updates some state then signals the event when done. -// The consumer will consume that state in the callback provided to unique_event_watcher. -// -// Note, multiple signals may coalesce into a single callback. -// -// Example use of throwing version: -// auto globalStateWatcher = wil::make_event_watcher([] -// { -// currentState = GetGlobalState(); -// }); -// -// UpdateGlobalState(value); -// globalStateWatcher.SetEvent(); // signal observers so they can update -// -// Example use of non-throwing version: -// auto globalStateWatcher = wil::make_event_watcher_nothrow([] -// { -// currentState = GetGlobalState(); -// }); -// RETURN_IF_NULL_ALLOC(globalStateWatcher); -// -// UpdateGlobalState(value); -// globalStateWatcher.SetEvent(); // signal observers so they can update + // unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast + // + // Clients must include or to enable use of this class as it uses new(std::nothrow). + // This is to avoid the dependency on those headers that some clients can't tolerate. + // + // These classes makes it easy to execute a provided function when an event + // is signaled. It will create the event handle for you, take ownership of one + // or duplicate a handle provided. It supports the ability to signal the + // event using SetEvent() and SetEvent_scope_exit(); + // + // This can be used to support producer-consumer pattern + // where a producer updates some state then signals the event when done. + // The consumer will consume that state in the callback provided to unique_event_watcher. + // + // Note, multiple signals may coalesce into a single callback. + // + // Example use of throwing version: + // auto globalStateWatcher = wil::make_event_watcher([] + // { + // currentState = GetGlobalState(); + // }); + // + // UpdateGlobalState(value); + // globalStateWatcher.SetEvent(); // signal observers so they can update + // + // Example use of non-throwing version: + // auto globalStateWatcher = wil::make_event_watcher_nothrow([] + // { + // currentState = GetGlobalState(); + // }); + // RETURN_IF_NULL_ALLOC(globalStateWatcher); + // + // UpdateGlobalState(value); + // globalStateWatcher.SetEvent(); // signal observers so they can update -/// @cond -namespace details -{ - struct event_watcher_state + /// @cond + namespace details { - event_watcher_state(unique_event_nothrow&& eventHandle, wistd::function&& callback) : - m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle)) + struct event_watcher_state + { + event_watcher_state(unique_event_nothrow &&eventHandle, wistd::function &&callback) + : m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle)) + { + } + wistd::function m_callback; + unique_event_nothrow m_event; + // The thread pool must be last to ensure that the other members are valid + // when it is destructed as it will reference them. + unique_threadpool_wait m_threadPoolWait; + }; + + inline void delete_event_watcher_state(_In_opt_ event_watcher_state *watcherStorage) + { + delete watcherStorage; + } + + typedef resource_policy + event_watcher_state_resource_policy; + } // namespace details + /// @endcond + + template class event_watcher_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit event_watcher_t(args_t &&...args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) { } - wistd::function m_callback; - unique_event_nothrow m_event; - // The thread pool must be last to ensure that the other members are valid - // when it is destructed as it will reference them. - unique_threadpool_wait m_threadPoolWait; + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + template + event_watcher_t(unique_any_t, from_err_policy>> + &&eventHandle, + wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(wistd::move(eventHandle), wistd::move(callback)); + } + + event_watcher_t(_In_ HANDLE eventHandle, wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(eventHandle, wistd::move(callback)); + } + + event_watcher_t(wistd::function &&callback) + { + static_assert(wistd::is_same::value, + "this constructor requires exceptions or fail fast; use the create method"); + create(wistd::move(callback)); + } + + template + result create(unique_any_t, event_err_policy>> + &&eventHandle, + wistd::function &&callback) + { + return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); + } + + // Creates the event that you will be watching. + result create(wistd::function &&callback) + { + unique_event_nothrow eventHandle; + HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too. + if (FAILED(hr)) + { + return err_policy::HResult(hr); + } + return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); + } + + // Input is an event handler that is duplicated into this class. + result create(_In_ HANDLE eventHandle, wistd::function &&callback) + { + unique_event_nothrow ownedHandle; + if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + return err_policy::LastError(); + } + return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback))); + } + + // Provide access to the inner event and the very common SetEvent() method on it. + WI_NODISCARD unique_event_nothrow const &get_event() const WI_NOEXCEPT + { + return storage_t::get()->m_event; + } + void SetEvent() const WI_NOEXCEPT + { + storage_t::get()->m_event.SetEvent(); + } + + private: + // Had to move this from a Lambda so it would compile in C++/CLI (which thought the Lambda should be a managed + // function for some reason). + static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *pThreadPoolWait, + TP_WAIT_RESULT) + { + auto pThis = static_cast(context); + // Manual events must be re-set to avoid missing the last notification. + pThis->m_event.ResetEvent(); + // Call the client before re-arming to ensure that multiple callbacks don't + // run concurrently. + pThis->m_callback(); + SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success + } + + // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base + // create function takes a raw handle and assumes its ownership, even on failure. + HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function &&callback) + { + __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter + unique_event_nothrow eventHandle(rawHandleOwnershipTaken); + wistd::unique_ptr watcherState( + new (std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + + watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + storage_t::reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr); + return S_OK; + } }; - inline void delete_event_watcher_state(_In_opt_ event_watcher_state* watcherStorage) + typedef unique_any_t< + event_watcher_t, err_returncode_policy>> + unique_event_watcher_nothrow; + typedef unique_any_t< + event_watcher_t, err_failfast_policy>> + unique_event_watcher_failfast; + + template + unique_event_watcher_nothrow make_event_watcher_nothrow( + unique_any_t, err_policy>> &&eventHandle, + wistd::function &&callback) WI_NOEXCEPT { - delete watcherStorage; + unique_event_watcher_nothrow watcher; + watcher.create(wistd::move(eventHandle), wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) } - typedef resource_policy event_watcher_state_resource_policy; -} // namespace details -/// @endcond - -template -class event_watcher_t : public storage_t -{ -public: - // forward all base class constructors... - template - explicit event_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) + inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, + wistd::function &&callback) WI_NOEXCEPT { + unique_event_watcher_nothrow watcher; + watcher.create(eventHandle, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) } - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - template - event_watcher_t( - unique_any_t, from_err_policy>>&& eventHandle, - wistd::function&& callback) + inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function &&callback) WI_NOEXCEPT { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(wistd::move(eventHandle), wistd::move(callback)); + unique_event_watcher_nothrow watcher; + watcher.create(wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) } - event_watcher_t(_In_ HANDLE eventHandle, wistd::function&& callback) + template + unique_event_watcher_failfast make_event_watcher_failfast( + unique_any_t, err_policy>> &&eventHandle, + wistd::function &&callback) { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(eventHandle, wistd::move(callback)); + return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback)); } - event_watcher_t(wistd::function&& callback) + inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, + wistd::function &&callback) { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(wistd::move(callback)); + return unique_event_watcher_failfast(eventHandle, wistd::move(callback)); } - template - result create( - unique_any_t, event_err_policy>>&& eventHandle, - wistd::function&& callback) + inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function &&callback) { - return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); + return unique_event_watcher_failfast(wistd::move(callback)); } - // Creates the event that you will be watching. - result create(wistd::function&& callback) - { - unique_event_nothrow eventHandle; - HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too. - if (FAILED(hr)) - { - return err_policy::HResult(hr); - } - return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); - } - - // Input is an event handler that is duplicated into this class. - result create(_In_ HANDLE eventHandle, wistd::function&& callback) - { - unique_event_nothrow ownedHandle; - if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - return err_policy::LastError(); - } - return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback))); - } - - // Provide access to the inner event and the very common SetEvent() method on it. - WI_NODISCARD unique_event_nothrow const& get_event() const WI_NOEXCEPT - { - return storage_t::get()->m_event; - } - void SetEvent() const WI_NOEXCEPT - { - storage_t::get()->m_event.SetEvent(); - } - -private: - // Had to move this from a Lambda so it would compile in C++/CLI (which thought the Lambda should be a managed function for some reason). - static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void* context, TP_WAIT* pThreadPoolWait, TP_WAIT_RESULT) - { - auto pThis = static_cast(context); - // Manual events must be re-set to avoid missing the last notification. - pThis->m_event.ResetEvent(); - // Call the client before re-arming to ensure that multiple callbacks don't - // run concurrently. - pThis->m_callback(); - SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success - } - - // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base - // create function takes a raw handle and assumes its ownership, even on failure. - HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function&& callback) - { - __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter - unique_event_nothrow eventHandle(rawHandleOwnershipTaken); - wistd::unique_ptr watcherState( - new (std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - storage_t::reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr); - return S_OK; - } -}; - -typedef unique_any_t, err_returncode_policy>> unique_event_watcher_nothrow; -typedef unique_any_t, err_failfast_policy>> unique_event_watcher_failfast; - -template -unique_event_watcher_nothrow make_event_watcher_nothrow( - unique_any_t, err_policy>>&& eventHandle, - wistd::function&& callback) WI_NOEXCEPT -{ - unique_event_watcher_nothrow watcher; - watcher.create(wistd::move(eventHandle), wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} - -inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, wistd::function&& callback) WI_NOEXCEPT -{ - unique_event_watcher_nothrow watcher; - watcher.create(eventHandle, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} - -inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function&& callback) WI_NOEXCEPT -{ - unique_event_watcher_nothrow watcher; - watcher.create(wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) -} - -template -unique_event_watcher_failfast make_event_watcher_failfast( - unique_any_t, err_policy>>&& eventHandle, - wistd::function&& callback) -{ - return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback)); -} - -inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, wistd::function&& callback) -{ - return unique_event_watcher_failfast(eventHandle, wistd::move(callback)); -} - -inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function&& callback) -{ - return unique_event_watcher_failfast(wistd::move(callback)); -} - #ifdef WIL_ENABLE_EXCEPTIONS -typedef unique_any_t, err_exception_policy>> unique_event_watcher; + typedef unique_any_t< + event_watcher_t, err_exception_policy>> + unique_event_watcher; -template -unique_event_watcher make_event_watcher( - unique_any_t, err_policy>>&& eventHandle, - wistd::function&& callback) -{ - return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback)); -} + template + unique_event_watcher make_event_watcher( + unique_any_t, err_policy>> &&eventHandle, + wistd::function &&callback) + { + return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback)); + } -inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function&& callback) -{ - return unique_event_watcher(eventHandle, wistd::move(callback)); -} + inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function &&callback) + { + return unique_event_watcher(eventHandle, wistd::move(callback)); + } -inline unique_event_watcher make_event_watcher(wistd::function&& callback) -{ - return unique_event_watcher(wistd::move(callback)); -} + inline unique_event_watcher make_event_watcher(wistd::function &&callback) + { + return unique_event_watcher(wistd::move(callback)); + } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_WINBASE_NOTHROW_T_DEFINED @@ -4018,956 +4039,1002 @@ inline unique_event_watcher make_event_watcher(wistd::function&& callbac #if (defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_STL -/// @endcond -typedef shared_any_t>> shared_event; -typedef shared_any_t>> shared_mutex; -typedef shared_any_t>> shared_semaphore; -typedef shared_any shared_hfile; -typedef shared_any shared_handle; -typedef shared_any shared_hfind; -typedef shared_any shared_hmodule; + /// @endcond + typedef shared_any_t>> shared_event; + typedef shared_any_t>> shared_mutex; + typedef shared_any_t>> shared_semaphore; + typedef shared_any shared_hfile; + typedef shared_any shared_handle; + typedef shared_any shared_hfind; + typedef shared_any shared_hmodule; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -typedef shared_any shared_threadpool_wait; -typedef shared_any shared_threadpool_wait_nocancel; -typedef shared_any shared_threadpool_work; -typedef shared_any shared_threadpool_work_nocancel; + typedef shared_any shared_threadpool_wait; + typedef shared_any shared_threadpool_wait_nocancel; + typedef shared_any shared_threadpool_work; + typedef shared_any shared_threadpool_work_nocancel; -typedef shared_any shared_hfind_change; + typedef shared_any shared_hfind_change; #endif -typedef weak_any weak_event; -typedef weak_any weak_mutex; -typedef weak_any weak_semaphore; -typedef weak_any weak_hfile; -typedef weak_any weak_handle; -typedef weak_any weak_hfind; -typedef weak_any weak_hmodule; + typedef weak_any weak_event; + typedef weak_any weak_mutex; + typedef weak_any weak_semaphore; + typedef weak_any weak_hfile; + typedef weak_any weak_handle; + typedef weak_any weak_hfind; + typedef weak_any weak_hmodule; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -typedef weak_any weak_threadpool_wait; -typedef weak_any weak_threadpool_wait_nocancel; -typedef weak_any weak_threadpool_work; -typedef weak_any weak_threadpool_work_nocancel; + typedef weak_any weak_threadpool_wait; + typedef weak_any weak_threadpool_wait_nocancel; + typedef weak_any weak_threadpool_work; + typedef weak_any weak_threadpool_work_nocancel; -typedef weak_any weak_hfind_change; + typedef weak_any weak_hfind_change; #endif #endif // __WIL_WINBASE_STL -#if (defined(_HEAPAPI_H_) && !defined(__WIL__WIL_HEAP_API) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_HEAPAPI_H_) && !defined(__WIL__WIL_HEAP_API) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__WIL_HEAP_API -/// @endcond + /// @endcond -template -using unique_process_heap_ptr = wistd::unique_ptr, process_heap_deleter>; -typedef unique_any unique_process_heap; -typedef unique_any unique_process_heap_string; + template + using unique_process_heap_ptr = + wistd::unique_ptr, process_heap_deleter>; + typedef unique_any unique_process_heap; + typedef unique_any unique_process_heap_string; #ifndef WIL_NO_ANSI_STRINGS -typedef unique_any unique_process_heap_ansistring; + typedef unique_any + unique_process_heap_ansistring; #endif // WIL_NO_ANSI_STRINGS -/// @cond -namespace details -{ - template <> - struct string_allocator : heap_allocator + /// @cond + namespace details { - }; + template <> struct string_allocator : heap_allocator + { + }; #ifndef WIL_NO_ANSI_STRINGS - template <> - struct string_allocator : heap_allocator - { - }; + template <> struct string_allocator : heap_allocator + { + }; #endif -} // namespace details -/// @endcond + } // namespace details + /// @endcond -inline auto make_process_heap_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_nothrow(source, length); -} + inline auto make_process_heap_string_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } -inline auto make_process_heap_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_failfast(source, length); -} + inline auto make_process_heap_string_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } #ifndef WIL_NO_ANSI_STRINGS -inline auto make_process_heap_ansistring_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_ansistring_nothrow(source, length); -} + inline auto make_process_heap_ansistring_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_nothrow(source, length); + } -inline auto make_process_heap_ansistring_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_ansistring_failfast(source, length); -} + inline auto make_process_heap_ansistring_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_failfast(source, length); + } #endif // WIL_NO_ANSI_STRINGS #ifdef WIL_ENABLE_EXCEPTIONS -inline auto make_process_heap_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) -{ - return make_unique_string(source, length); -} + inline auto make_process_heap_string(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } #ifndef WIL_NO_ANSI_STRINGS -inline auto make_process_heap_ansistring( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) -{ - return make_unique_ansistring(source, length); -} + inline auto make_process_heap_ansistring(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCSTR source, + size_t length = static_cast(-1)) + { + return make_unique_ansistring(source, length); + } #endif // WIL_NO_ANSI_STRINGS #endif // WIL_ENABLE_EXCEPTIONS #endif // _HEAPAPI_H_ -#if (defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED_STL) && defined(WIL_RESOURCE_STL) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED_STL) && \ + defined(WIL_RESOURCE_STL) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_NOTHROW_T_DEFINED_STL -/// @endcond -typedef shared_any_t>> shared_event_watcher; -typedef weak_any weak_event_watcher; + /// @endcond + typedef shared_any_t>> shared_event_watcher; + typedef weak_any weak_event_watcher; #endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL -#if (defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_DESKTOP -namespace details -{ - inline void __stdcall DestroyPrivateObjectSecurity(_Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT + namespace details { - ::DestroyPrivateObjectSecurity(&pObjectDescriptor); - } -} // namespace details -/// @endcond - -using hlocal_deleter = function_deleter; - -template -using unique_hlocal_ptr = wistd::unique_ptr, hlocal_deleter>; - -template -using unique_hlocal_array_ptr = wil::unique_array_ptr; - -/** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not throw upon -allocation failure. Use `wil::make_unique_hlocal_nothrow()` for resources returned from APIs that must satisfy a memory allocation -contract that requires the use of `LocalAlloc()` / `LocalFree()`. Use `wil::make_unique_nothrow()` when `LocalAlloc()` is not -required. - -Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee -initialization. - -Note that `wil::make_unique_hlocal_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that -may throw in its constructor. -@code -auto foo = wil::make_unique_hlocal_nothrow(); -if (foo) -{ -// initialize allocated Foo object as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(Args&&... args) -{ - unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, sizeof(T)))); - if (sp) - { - // use placement new to initialize memory from the previous allocation - new (sp.get()) T(wistd::forward(args)...); - } - return sp; -} - -/** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may not throw upon -allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal_nothrow(size); -if (foos) -{ -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_nothrow( - size_t size) -{ - typedef typename wistd::remove_extent::type E; - FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); - size_t allocSize = sizeof(E) * size; - unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, allocSize))); - if (sp) - { - // use placement new to initialize memory from the previous allocation; - // note that array placement new cannot be used as the standard allows for operator new[] - // to consume overhead in the allocation for internal bookkeeping - for (auto& elem : make_range(static_cast(sp.get()), size)) + inline void __stdcall DestroyPrivateObjectSecurity( + _Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT { - new (&elem) E(); + ::DestroyPrivateObjectSecurity(&pObjectDescriptor); } + } // namespace details + /// @endcond + + using hlocal_deleter = function_deleter; + + template + using unique_hlocal_ptr = wistd::unique_ptr, hlocal_deleter>; + + template using unique_hlocal_array_ptr = wil::unique_array_ptr; + + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not + throw upon allocation failure. Use `wil::make_unique_hlocal_nothrow()` for resources returned from APIs that must + satisfy a memory allocation contract that requires the use of `LocalAlloc()` / `LocalFree()`. Use + `wil::make_unique_nothrow()` when `LocalAlloc()` is not required. + + Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee + initialization. + + Note that `wil::make_unique_hlocal_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an + exception-based class that may throw in its constructor. + @code + auto foo = wil::make_unique_hlocal_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate } - return sp; -} - -/** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail fast upon -allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_hlocal_failfast(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_failfast(Args&&... args) -{ - unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} - -/** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must fail fast -upon allocation failure. -See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal_failfast(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_failfast( - size_t size) -{ - unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -/** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`. -See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_hlocal(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal(Args&&... args) -{ - unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; -} - -/** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`. -See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal(size_t size) -{ - unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; -} -#endif // WIL_ENABLE_EXCEPTIONS - -typedef unique_any unique_hlocal; -typedef unique_any unique_hlocal_string; -#ifndef WIL_NO_ANSI_STRINGS -typedef unique_any unique_hlocal_ansistring; -#endif // WIL_NO_ANSI_STRINGS - -/// @cond -namespace details -{ - struct localalloc_allocator + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_nothrow( + Args &&...args) { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, sizeof(T)))); + if (sp) { - return ::LocalAlloc(LMEM_FIXED, size); + // use placement new to initialize memory from the previous allocation + new (sp.get()) T(wistd::forward(args)...); } - }; + return sp; + } - template <> - struct string_allocator : localalloc_allocator + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may + not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for + more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal_nothrow(size); + if (foos) { - }; -#ifndef WIL_NO_ANSI_STRINGS - template <> - struct string_allocator : localalloc_allocator + for (auto& elem : wil::make_range(foos.get(), size)) { - }; -#endif // WIL_NO_ANSI_STRINGS -} // namespace details -/// @endcond - -inline auto make_hlocal_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_nothrow(source, length); -} - -inline auto make_hlocal_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_failfast(source, length); -} - -#ifndef WIL_NO_ANSI_STRINGS -inline auto make_hlocal_ansistring_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_ansistring_nothrow(source, length); -} - -inline auto make_hlocal_ansistring_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_ansistring_failfast(source, length); -} -#endif - -#ifdef WIL_ENABLE_EXCEPTIONS -inline auto make_hlocal_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) -{ - return make_unique_string(source, length); -} - -#ifndef WIL_NO_ANSI_STRINGS -inline auto make_hlocal_ansistring( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCSTR source, - size_t length = static_cast(-1)) -{ - return make_unique_ansistring(source, length); -} -#endif // WIL_NO_ANSI_STRINGS -#endif // WIL_ENABLE_EXCEPTIONS - -struct hlocal_secure_deleter -{ + // initialize allocated Foo objects as appropriate + } + } + @endcode + */ template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + inline + typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type + make_unique_hlocal_nothrow(size_t size) { - if (p) + typedef typename wistd::remove_extent::type E; + FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); + size_t allocSize = sizeof(E) * size; + unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, allocSize))); + if (sp) { -#pragma warning(suppress : 26006 26007) // LocalSize() ensures proper buffer length - ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure - ::LocalFree(p); + // use placement new to initialize memory from the previous allocation; + // note that array placement new cannot be used as the standard allows for operator new[] + // to consume overhead in the allocation for internal bookkeeping + for (auto &elem : make_range(static_cast(sp.get()), size)) + { + new (&elem) E(); + } } + return sp; } -}; -template -using unique_hlocal_secure_ptr = wistd::unique_ptr, hlocal_secure_deleter>; + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail + fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more + details. + @code + auto foo = wil::make_unique_hlocal_failfast(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type + make_unique_hlocal_failfast(Args &&...args) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } -/** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may not throw -upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_hlocal_secure_nothrow(); -if (foo) -{ -// initialize allocated Foo object as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(Args&&... args) -{ - return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(wistd::forward(args)...).release()); -} - -/** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that may not -throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal_secure_nothrow(size); -if (foos) -{ -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow( - size_t size) -{ - return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(size).release()); -} - -/** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that must fail fast -upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_hlocal_secure_failfast(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(Args&&... args) -{ - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} - -/** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that must fail -fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal_secure_failfast(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast( - size_t size) -{ - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must + fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for + more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline + typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type + make_unique_hlocal_failfast(size_t size) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`. -See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_hlocal_secure(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(Args&&... args) -{ - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + @code + auto foo = wil::make_unique_hlocal(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal( + Args &&...args) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } -/** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`. -See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_hlocal_secure(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure( - size_t size) -{ - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline + typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type + make_unique_hlocal(size_t size) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -typedef unique_hlocal_secure_ptr unique_hlocal_string_secure; - -/** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon allocation -failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_hlocal_string_secure_nothrow(L"a string"); -RETURN_IF_NULL_ALLOC(str); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -~~~ -*/ -inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT -{ - return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release()); -} - -/** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon allocation -failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_hlocal_string_secure_failfast(L"a string"); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -~~~ -*/ -inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT -{ - unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} - -#ifdef WIL_ENABLE_EXCEPTIONS -/** Copies a given string into secure memory allocated with `LocalAlloc()`. -See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_hlocal_string_secure(L"a string"); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -~~~ -*/ -inline auto make_hlocal_string_secure(_In_ PCWSTR source) -{ - unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; -} -#endif - -using hglobal_deleter = function_deleter; - -template -using unique_hglobal_ptr = wistd::unique_ptr, hglobal_deleter>; - -typedef unique_any unique_hglobal; -typedef unique_any unique_hglobal_string; + typedef unique_any unique_hlocal; + typedef unique_any unique_hlocal_string; #ifndef WIL_NO_ANSI_STRINGS -typedef unique_any unique_hglobal_ansistring; + typedef unique_any unique_hlocal_ansistring; #endif // WIL_NO_ANSI_STRINGS -/// @cond -namespace details -{ - template <> - struct string_allocator + /// @cond + namespace details { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + struct localalloc_allocator { - return ::GlobalAlloc(GPTR, size); + static _Ret_opt_bytecap_(size) void *allocate(size_t size) WI_NOEXCEPT + { + return ::LocalAlloc(LMEM_FIXED, size); + } + }; + + template <> struct string_allocator : localalloc_allocator + { + }; +#ifndef WIL_NO_ANSI_STRINGS + template <> struct string_allocator : localalloc_allocator + { + }; +#endif // WIL_NO_ANSI_STRINGS + } // namespace details + /// @endcond + + inline auto make_hlocal_string_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } + + inline auto make_hlocal_string_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } + +#ifndef WIL_NO_ANSI_STRINGS + inline auto make_hlocal_ansistring_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_nothrow(source, length); + } + + inline auto make_hlocal_ansistring_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_failfast(source, length); + } +#endif + +#ifdef WIL_ENABLE_EXCEPTIONS + inline auto make_hlocal_string(_When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } + +#ifndef WIL_NO_ANSI_STRINGS + inline auto make_hlocal_ansistring(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, + size_t length = static_cast(-1)) + { + return make_unique_ansistring(source, length); + } +#endif // WIL_NO_ANSI_STRINGS +#endif // WIL_ENABLE_EXCEPTIONS + + struct hlocal_secure_deleter + { + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T *p) const + { + if (p) + { +#pragma warning(suppress : 26006 26007) // LocalSize() ensures proper buffer length + ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure + ::LocalFree(p); + } } }; -} // namespace details -/// @endcond -typedef unique_any_handle_null unique_hheap; -typedef unique_any unique_tls; -typedef unique_any unique_hlocal_security_descriptor; -typedef unique_any unique_private_security_descriptor; + template + using unique_hlocal_secure_ptr = + wistd::unique_ptr, hlocal_secure_deleter>; + + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may + not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for + more details. + @code + auto foo = wil::make_unique_hlocal_secure_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure_nothrow(Args &&...args) + { + return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(wistd::forward(args)...).release()); + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context + that may not throw upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array + types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure_nothrow(size_t size) + { + return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(size).release()); + } + + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that + must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types + for more details. + @code + auto foo = wil::make_unique_hlocal_secure_failfast(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure_failfast(Args &&...args) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context + that must fail fast upon allocation failure. See the overload of `wil::make_unique_hlocal_nothrow()` for non-array + types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure_failfast(size_t size) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + @code + auto foo = wil::make_unique_hlocal_secure(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure(Args &&...args) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_hlocal_secure_ptr>::type + make_unique_hlocal_secure(size_t size) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_hlocal_secure_ptr unique_hlocal_string_secure; + + /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon + allocation failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure_nothrow(L"a string"); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT + { + return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release()); + } + + /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon + allocation failure. See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure_failfast(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT + { + unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Copies a given string into secure memory allocated with `LocalAlloc()`. + See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure(_In_ PCWSTR source) + { + unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif + + using hglobal_deleter = function_deleter; + + template + using unique_hglobal_ptr = wistd::unique_ptr, hglobal_deleter>; + + typedef unique_any unique_hglobal; + typedef unique_any unique_hglobal_string; +#ifndef WIL_NO_ANSI_STRINGS + typedef unique_any unique_hglobal_ansistring; +#endif // WIL_NO_ANSI_STRINGS + + /// @cond + namespace details + { + template <> struct string_allocator + { + static _Ret_opt_bytecap_(size) void *allocate(size_t size) WI_NOEXCEPT + { + return ::GlobalAlloc(GPTR, size); + } + }; + } // namespace details + /// @endcond + + typedef unique_any_handle_null unique_hheap; + typedef unique_any + unique_tls; + typedef unique_any unique_hlocal_security_descriptor; + typedef unique_any + unique_private_security_descriptor; #if (defined(_WINUSER_) && !defined(__WIL__WINUSER_)) || defined(WIL_DOXYGEN) /// @cond #define __WIL__WINUSER_ -/// @endcond -typedef unique_any unique_haccel; -typedef unique_any unique_hcursor; -typedef unique_any unique_hwnd; + /// @endcond + typedef unique_any unique_haccel; + typedef unique_any unique_hcursor; + typedef unique_any unique_hwnd; #if !defined(NOUSER) && !defined(NOWH) -typedef unique_any unique_hhook; + typedef unique_any unique_hhook; #endif #if !defined(NOWINABLE) -typedef unique_any unique_hwineventhook; + typedef unique_any unique_hwineventhook; #endif #if !defined(NOCLIPBOARD) -using unique_close_clipboard_call = unique_call; + using unique_close_clipboard_call = unique_call; -inline unique_close_clipboard_call open_clipboard(HWND hwnd) -{ - return unique_close_clipboard_call{OpenClipboard(hwnd) != FALSE}; -} + inline unique_close_clipboard_call open_clipboard(HWND hwnd) + { + return unique_close_clipboard_call{OpenClipboard(hwnd) != FALSE}; + } #endif #endif // __WIL__WINUSER_ #if !defined(NOGDI) && !defined(NODESKTOP) -typedef unique_any unique_hdesk; -typedef unique_any unique_hwinsta; + typedef unique_any unique_hdesk; + typedef unique_any unique_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) #endif -#if (defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WINBASE_DESKTOP_STL -/// @endcond -typedef shared_any shared_hheap; -typedef shared_any shared_hlocal; -typedef shared_any shared_tls; -typedef shared_any shared_hlocal_security_descriptor; -typedef shared_any shared_private_security_descriptor; -typedef shared_any shared_haccel; -typedef shared_any shared_hcursor; + /// @endcond + typedef shared_any shared_hheap; + typedef shared_any shared_hlocal; + typedef shared_any shared_tls; + typedef shared_any shared_hlocal_security_descriptor; + typedef shared_any shared_private_security_descriptor; + typedef shared_any shared_haccel; + typedef shared_any shared_hcursor; #if !defined(NOGDI) && !defined(NODESKTOP) -typedef shared_any shared_hdesk; -typedef shared_any shared_hwinsta; + typedef shared_any shared_hdesk; + typedef shared_any shared_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) -typedef shared_any shared_hwnd; + typedef shared_any shared_hwnd; #if !defined(NOUSER) && !defined(NOWH) -typedef shared_any shared_hhook; + typedef shared_any shared_hhook; #endif #if !defined(NOWINABLE) -typedef shared_any shared_hwineventhook; + typedef shared_any shared_hwineventhook; #endif -typedef weak_any weak_hheap; -typedef weak_any weak_hlocal; -typedef weak_any weak_tls; -typedef weak_any weak_hlocal_security_descriptor; -typedef weak_any weak_private_security_descriptor; -typedef weak_any weak_haccel; -typedef weak_any weak_hcursor; + typedef weak_any weak_hheap; + typedef weak_any weak_hlocal; + typedef weak_any weak_tls; + typedef weak_any weak_hlocal_security_descriptor; + typedef weak_any weak_private_security_descriptor; + typedef weak_any weak_haccel; + typedef weak_any weak_hcursor; #if !defined(NOGDI) && !defined(NODESKTOP) -typedef weak_any weak_hdesk; -typedef weak_any weak_hwinsta; + typedef weak_any weak_hdesk; + typedef weak_any weak_hwinsta; #endif // !defined(NOGDI) && !defined(NODESKTOP) -typedef weak_any weak_hwnd; + typedef weak_any weak_hwnd; #if !defined(NOUSER) && !defined(NOWH) -typedef weak_any weak_hhook; + typedef weak_any weak_hhook; #endif #if !defined(NOWINABLE) -typedef weak_any weak_hwineventhook; + typedef weak_any weak_hwineventhook; #endif #endif // __WIL_WINBASE_DESKTOP_STL -#if (defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__COMBASEAPI_H_ /// @endcond #if (NTDDI_VERSION >= NTDDI_WIN8) -typedef unique_any unique_mta_usage_cookie; + typedef unique_any + unique_mta_usage_cookie; #endif -typedef unique_any unique_com_class_object_cookie; + typedef unique_any unique_com_class_object_cookie; -/// @cond -namespace details -{ - inline void __stdcall MultiQiCleanup(_In_ MULTI_QI* multiQi) + /// @cond + namespace details { - if (multiQi->pItf) + inline void __stdcall MultiQiCleanup(_In_ MULTI_QI *multiQi) { - multiQi->pItf->Release(); - multiQi->pItf = nullptr; + if (multiQi->pItf) + { + multiQi->pItf->Release(); + multiQi->pItf = nullptr; + } } + } // namespace details + /// @endcond + + //! A type that calls CoRevertToSelf on destruction (or reset()). + using unique_coreverttoself_call = unique_call; + + //! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts + WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast() + { + FAIL_FAST_IF_FAILED(::CoImpersonateClient()); + return unique_coreverttoself_call(); } -} // namespace details -/// @endcond - -//! A type that calls CoRevertToSelf on destruction (or reset()). -using unique_coreverttoself_call = unique_call; - -//! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts -WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast() -{ - FAIL_FAST_IF_FAILED(::CoImpersonateClient()); - return unique_coreverttoself_call(); -} #ifdef WIL_ENABLE_EXCEPTIONS -WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient() -{ - THROW_IF_FAILED(::CoImpersonateClient()); - return unique_coreverttoself_call(); -} + WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient() + { + THROW_IF_FAILED(::CoImpersonateClient()); + return unique_coreverttoself_call(); + } #endif -typedef unique_struct unique_multi_qi; + typedef unique_struct unique_multi_qi; #endif // __WIL__COMBASEAPI_H_ -#if (defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8)) || \ +#if (defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && \ + (NTDDI_VERSION >= NTDDI_WIN8)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__COMBASEAPI_H__STL -/// @endcond -typedef shared_any shared_mta_usage_cookie; -typedef weak_any weak_mta_usage_cookie; + /// @endcond + typedef shared_any shared_mta_usage_cookie; + typedef weak_any weak_mta_usage_cookie; #endif // __WIL__COMBASEAPI_H__STL -#if (defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__COMBASEAPI_H_APP -/// @endcond -//! A type that calls CoUninitialize on destruction (or reset()). -using unique_couninitialize_call = unique_call; + /// @endcond + //! A type that calls CoUninitialize on destruction (or reset()). + using unique_couninitialize_call = unique_call; -//! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts -WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) -{ - FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); - return {}; -} + //! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts + WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast( + DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) + { + FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); + return {}; + } #ifdef WIL_ENABLE_EXCEPTIONS -WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) -{ - THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); - return {}; -} + WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) + { + THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); + return {}; + } #endif #endif // __WIL__COMBASEAPI_H_APP -#if (defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8)) || \ +#if (defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__ROAPI_H_APP -/// @endcond + /// @endcond -typedef unique_any unique_ro_registration_cookie; + typedef unique_any + unique_ro_registration_cookie; -//! A type that calls RoUninitialize on destruction (or reset()). -//! Use as a replacement for Windows::Foundation::Uninitialize. -using unique_rouninitialize_call = unique_call; + //! A type that calls RoUninitialize on destruction (or reset()). + //! Use as a replacement for Windows::Foundation::Uninitialize. + using unique_rouninitialize_call = unique_call; -//! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts -//! Use as a replacement for Windows::Foundation::Initialize -WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) -{ - FAIL_FAST_IF_FAILED(::RoInitialize(initType)); - return unique_rouninitialize_call(); -} + //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) + { + FAIL_FAST_IF_FAILED(::RoInitialize(initType)); + return unique_rouninitialize_call(); + } #ifdef WIL_ENABLE_EXCEPTIONS -//! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts -//! Use as a replacement for Windows::Foundation::Initialize -WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) -{ - THROW_IF_FAILED(::RoInitialize(initType)); - return unique_rouninitialize_call(); -} + //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) + { + THROW_IF_FAILED(::RoInitialize(initType)); + return unique_rouninitialize_call(); + } #endif #endif // __WIL__ROAPI_H_APP -#if (defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ +#if (defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__WINSTRING_H_ -/// @endcond -typedef unique_any unique_hstring; + /// @endcond + typedef unique_any unique_hstring; -template <> -inline unique_hstring make_unique_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length) WI_NOEXCEPT -{ - WI_ASSERT(source != nullptr); // the HSTRING version of this function does not support this case - if (length == static_cast(-1)) + template <> + inline unique_hstring make_unique_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, + size_t length) WI_NOEXCEPT { - length = wcslen(source); + WI_ASSERT(source != nullptr); // the HSTRING version of this function does not support this case + if (length == static_cast(-1)) + { + length = wcslen(source); + } + + unique_hstring result; + ::WindowsCreateString(source, static_cast(length), &result); + return result; } - unique_hstring result; - ::WindowsCreateString(source, static_cast(length), &result); - return result; -} + typedef unique_any + unique_hstring_buffer; -typedef unique_any unique_hstring_buffer; - -/** Promotes an hstring_buffer to an HSTRING. -When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the -HSTRING afterwards. -~~~ -HRESULT Type::MakePath(_Out_ HSTRING* path) -{ - wchar_t* bufferStorage = nullptr; - wil::unique_hstring_buffer theBuffer; - RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); - RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); - RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path))); - return S_OK; -} -~~~ -*/ -inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer&& source, _Out_ HSTRING* promoted) -{ - HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted); - if (SUCCEEDED(hr)) + /** Promotes an hstring_buffer to an HSTRING. + When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller + owns the HSTRING afterwards. + ~~~ + HRESULT Type::MakePath(_Out_ HSTRING* path) { - source.release(); + wchar_t* bufferStorage = nullptr; + wil::unique_hstring_buffer theBuffer; + RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); + RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); + RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path))); + return S_OK; + } + ~~~ + */ + inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer &&source, _Out_ HSTRING *promoted) + { + HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted); + if (SUCCEEDED(hr)) + { + source.release(); + } + return hr; } - return hr; -} -//! A fail-fast variant of `make_hstring_from_buffer_nothrow` -inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer&& source) -{ - unique_hstring result; - FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); - return result; -} + //! A fail-fast variant of `make_hstring_from_buffer_nothrow` + inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer &&source) + { + unique_hstring result; + FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); + return result; + } #if defined WIL_ENABLE_EXCEPTIONS -/** Promotes an hstring_buffer to an HSTRING. -When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the -HSTRING afterwards. -~~~ -wil::unique_hstring Type::Make() -{ - wchar_t* bufferStorage = nullptr; - wil::unique_hstring_buffer theBuffer; - THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); - THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); - return wil::make_hstring_from_buffer(wistd::move(theBuffer)); -} -~~~ -*/ -inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer&& source) -{ - unique_hstring result; - THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); - return result; -} + /** Promotes an hstring_buffer to an HSTRING. + When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller + owns the HSTRING afterwards. + ~~~ + wil::unique_hstring Type::Make() + { + wchar_t* bufferStorage = nullptr; + wil::unique_hstring_buffer theBuffer; + THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); + THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); + return wil::make_hstring_from_buffer(wistd::move(theBuffer)); + } + ~~~ + */ + inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer &&source) + { + unique_hstring result; + THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); + return result; + } #endif -/// @cond -namespace details -{ - template <> - struct string_maker + /// @cond + namespace details { - string_maker() = default; - string_maker(const string_maker&) = delete; - void operator=(const string_maker&) = delete; - string_maker& operator=(string_maker&& source) WI_NOEXCEPT + template <> struct string_maker { - m_value = wistd::move(source.m_value); - m_bufferHandle = wistd::move(source.m_bufferHandle); - m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr); - return *this; - } - - HRESULT make( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) const wchar_t* source, - size_t length) - { - if (source) + string_maker() = default; + string_maker(const string_maker &) = delete; + void operator=(const string_maker &) = delete; + string_maker &operator=(string_maker &&source) WI_NOEXCEPT + { + m_value = wistd::move(source.m_value); + m_bufferHandle = wistd::move(source.m_bufferHandle); + m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr); + return *this; + } + + HRESULT make(_When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t *source, + size_t length) + { + if (source) + { + RETURN_IF_FAILED(WindowsCreateString(source, static_cast(length), &m_value)); + m_charBuffer = nullptr; + m_bufferHandle.reset(); // do this after WindowsCreateString so we can trim_at_existing_null() from + // our own buffer + } + else + { + // Need to set it to the empty string to support the empty string case. + m_value.reset(); + RETURN_IF_FAILED( + WindowsPreallocateStringBuffer(static_cast(length), &m_charBuffer, &m_bufferHandle)); + } + return S_OK; + } + + WI_NODISCARD wchar_t *buffer() + { + WI_ASSERT(m_charBuffer != nullptr); + return m_charBuffer; + } + WI_NODISCARD const wchar_t *buffer() const + { + return m_charBuffer; + } + + HRESULT trim_at_existing_null(size_t length) + { + return make(buffer(), length); + } + + unique_hstring release() { - RETURN_IF_FAILED(WindowsCreateString(source, static_cast(length), &m_value)); m_charBuffer = nullptr; - m_bufferHandle.reset(); // do this after WindowsCreateString so we can trim_at_existing_null() from our own buffer + if (m_bufferHandle) + { + return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle)); + } + return wistd::move(m_value); } - else + + static PCWSTR get(const wil::unique_hstring &value) { - // Need to set it to the empty string to support the empty string case. - m_value.reset(); - RETURN_IF_FAILED(WindowsPreallocateStringBuffer(static_cast(length), &m_charBuffer, &m_bufferHandle)); + return WindowsGetStringRawBuffer(value.get(), nullptr); } - return S_OK; - } - WI_NODISCARD wchar_t* buffer() - { - WI_ASSERT(m_charBuffer != nullptr); - return m_charBuffer; - } - WI_NODISCARD const wchar_t* buffer() const - { - return m_charBuffer; - } + private: + unique_hstring m_value; + unique_hstring_buffer m_bufferHandle; + wchar_t *m_charBuffer = nullptr; + }; + } // namespace details + /// @endcond - HRESULT trim_at_existing_null(size_t length) - { - return make(buffer(), length); - } + // 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 HSTRING. Other overloads available above. + inline PCWSTR str_raw_ptr(HSTRING str) + { + return WindowsGetStringRawBuffer(str, nullptr); + } - unique_hstring release() - { - m_charBuffer = nullptr; - if (m_bufferHandle) - { - return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle)); - } - return wistd::move(m_value); - } - - static PCWSTR get(const wil::unique_hstring& value) - { - return WindowsGetStringRawBuffer(value.get(), nullptr); - } - - private: - unique_hstring m_value; - unique_hstring_buffer m_bufferHandle; - wchar_t* m_charBuffer = nullptr; - }; -} // 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 HSTRING. Other overloads available above. -inline PCWSTR str_raw_ptr(HSTRING str) -{ - return WindowsGetStringRawBuffer(str, nullptr); -} - -inline PCWSTR str_raw_ptr(const unique_hstring& str) -{ - return str_raw_ptr(str.get()); -} + inline PCWSTR str_raw_ptr(const unique_hstring &str) + { + return str_raw_ptr(str.get()); + } #endif // __WIL__WINSTRING_H_ -#if (defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL__WINSTRING_H_STL -/// @endcond -typedef shared_any shared_hstring; -typedef shared_any shared_hstring_buffer; -typedef weak_any weak_hstring; -typedef weak_any weak_hstring_buffer; + /// @endcond + typedef shared_any shared_hstring; + typedef shared_any shared_hstring_buffer; + typedef weak_any weak_hstring; + typedef weak_any weak_hstring_buffer; #endif // __WIL__WINSTRING_H_STL -#if (defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WINREG_ -/// @endcond -typedef unique_any unique_hkey; + /// @endcond + typedef unique_any unique_hkey; #endif // __WIL_WINREG_ #if (defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINREG_STL -/// @endcond -typedef shared_any shared_hkey; -typedef weak_any weak_hkey; + /// @endcond + typedef shared_any shared_hkey; + typedef weak_any weak_hkey; #endif // __WIL_WINREG_STL #if (defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) @@ -4976,1295 +5043,1372 @@ typedef weak_any weak_hkey; /// @endcond // if language extensions (/Za) disabled, PropVariantInit will not exist, PROPVARIANT has forward declaration only #if defined(_MSC_EXTENSIONS) -using unique_prop_variant = - wil::unique_struct; + using unique_prop_variant = wil::unique_struct; #endif #endif // _WIL__propidl_h__ -#if (defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ +#if (defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_OLEAUTO_H_ -/// @endcond -using unique_variant = wil::unique_struct; -typedef unique_any unique_bstr; + /// @endcond + using unique_variant = + wil::unique_struct; + typedef unique_any unique_bstr; -inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT -{ - return wil::unique_bstr(::SysAllocString(source)); -} + inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT + { + return wil::unique_bstr(::SysAllocString(source)); + } -inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT -{ - return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source))); -} + inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT + { + return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source))); + } #ifdef WIL_ENABLE_EXCEPTIONS -inline wil::unique_bstr make_bstr(PCWSTR source) -{ - wil::unique_bstr result(make_bstr_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; -} + inline wil::unique_bstr make_bstr(PCWSTR source) + { + wil::unique_bstr result(make_bstr_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -inline wil::unique_variant make_variant_bstr_nothrow(PCWSTR source) WI_NOEXCEPT -{ - wil::unique_variant result{}; - V_UNION(result.addressof(), bstrVal) = ::SysAllocString(source); - if (V_UNION(result.addressof(), bstrVal) != nullptr) + inline wil::unique_variant make_variant_bstr_nothrow(PCWSTR source) WI_NOEXCEPT { - V_VT(result.addressof()) = VT_BSTR; + wil::unique_variant result{}; + V_UNION(result.addressof(), bstrVal) = ::SysAllocString(source); + if (V_UNION(result.addressof(), bstrVal) != nullptr) + { + V_VT(result.addressof()) = VT_BSTR; + } + return result; } - return result; -} -inline wil::unique_variant make_variant_bstr_failfast(PCWSTR source) WI_NOEXCEPT -{ - auto result{make_variant_bstr_nothrow(source)}; - FAIL_FAST_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); - return result; -} + inline wil::unique_variant make_variant_bstr_failfast(PCWSTR source) WI_NOEXCEPT + { + auto result{make_variant_bstr_nothrow(source)}; + FAIL_FAST_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -inline wil::unique_variant make_variant_bstr(PCWSTR source) -{ - auto result{make_variant_bstr_nothrow(source)}; - THROW_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); - return result; -} + inline wil::unique_variant make_variant_bstr(PCWSTR source) + { + auto result{make_variant_bstr_nothrow(source)}; + THROW_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_OLEAUTO_H_ #if (defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_OLEAUTO_H_STL -/// @endcond -typedef shared_any shared_bstr; -typedef weak_any weak_bstr; + /// @endcond + typedef shared_any shared_bstr; + typedef weak_any weak_bstr; #endif // __WIL_OLEAUTO_H_STL #if ((defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WININET_ -/// @endcond -typedef unique_any unique_hinternet; + /// @endcond + typedef unique_any unique_hinternet; #endif // __WIL_WININET_ #if (defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WININET_STL -/// @endcond -typedef shared_any shared_hinternet; -typedef weak_any weak_hinternet; + /// @endcond + typedef shared_any shared_hinternet; + typedef weak_any weak_hinternet; #endif // __WIL_WININET_STL #if (defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINHTTP_ -/// @endcond -typedef unique_any unique_winhttp_hinternet; + /// @endcond + typedef unique_any unique_winhttp_hinternet; #endif // __WIL_WINHTTP_ #if (defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINHTTP_STL -/// @endcond -typedef shared_any shared_winhttp_hinternet; -typedef weak_any weak_winhttp_hinternet; + /// @endcond + typedef shared_any shared_winhttp_hinternet; + typedef weak_any weak_winhttp_hinternet; #endif // __WIL_WINHTTP_STL -#if (defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WINSOCKAPI_ -/// @endcond -typedef unique_any unique_socket; + /// @endcond + typedef unique_any + unique_socket; #endif // __WIL_WINSOCKAPI_ #if (defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINSOCKAPI_STL -/// @endcond -typedef shared_any shared_socket; -typedef weak_any weak_socket; + /// @endcond + typedef shared_any shared_socket; + typedef weak_any weak_socket; #endif // __WIL_WINSOCKAPI_STL -#if (defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ + !defined(NOGDI) && !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WINGDI_ -/// @endcond -struct window_dc -{ - HDC dc; - HWND hwnd; - window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT + /// @endcond + struct window_dc { - dc = dc_; - hwnd = hwnd_; - } - WI_NODISCARD operator HDC() const WI_NOEXCEPT - { - return dc; - } - static void close(window_dc wdc) WI_NOEXCEPT - { - ::ReleaseDC(wdc.hwnd, wdc.dc); - } -}; -typedef unique_any unique_hdc_window; + HDC dc; + HWND hwnd; + window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT + { + dc = dc_; + hwnd = hwnd_; + } + WI_NODISCARD operator HDC() const WI_NOEXCEPT + { + return dc; + } + static void close(window_dc wdc) WI_NOEXCEPT + { + ::ReleaseDC(wdc.hwnd, wdc.dc); + } + }; + typedef unique_any + unique_hdc_window; -struct paint_dc -{ - HWND hwnd; - PAINTSTRUCT ps; - paint_dc(HDC hdc = nullptr) + struct paint_dc { - ::ZeroMemory(this, sizeof(*this)); - ps.hdc = hdc; - } - WI_NODISCARD operator HDC() const WI_NOEXCEPT + HWND hwnd; + PAINTSTRUCT ps; + paint_dc(HDC hdc = nullptr) + { + ::ZeroMemory(this, sizeof(*this)); + ps.hdc = hdc; + } + WI_NODISCARD operator HDC() const WI_NOEXCEPT + { + return ps.hdc; + } + static void close(paint_dc pdc) WI_NOEXCEPT + { + ::EndPaint(pdc.hwnd, &pdc.ps); + } + }; + typedef unique_any + unique_hdc_paint; + + struct select_result { - return ps.hdc; - } - static void close(paint_dc pdc) WI_NOEXCEPT + HGDIOBJ hgdi; + HDC hdc; + select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT + { + hgdi = hgdi_; + hdc = hdc_; + } + WI_NODISCARD operator HGDIOBJ() const WI_NOEXCEPT + { + return hgdi; + } + static void close(select_result sr) WI_NOEXCEPT + { + ::SelectObject(sr.hdc, sr.hgdi); + } + }; + typedef unique_any + unique_select_object; + + inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT { - ::EndPaint(pdc.hwnd, &pdc.ps); + return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd)); } -}; -typedef unique_any unique_hdc_paint; -struct select_result -{ - HGDIOBJ hgdi; - HDC hdc; - select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT + inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT { - hgdi = hgdi_; - hdc = hdc_; + return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd)); } - WI_NODISCARD operator HGDIOBJ() const WI_NOEXCEPT + + inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT { - return hgdi; + paint_dc pdc; + pdc.hwnd = hwnd; + HDC hdc = ::BeginPaint(hwnd, &pdc.ps); + assign_to_opt_param(pPaintStruct, pdc.ps); + return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc); } - static void close(select_result sr) WI_NOEXCEPT + + inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT { - ::SelectObject(sr.hdc, sr.hgdi); + return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc)); } -}; -typedef unique_any unique_select_object; -inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT -{ - return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd)); -} - -inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT -{ - return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd)); -} - -inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT -{ - paint_dc pdc; - pdc.hwnd = hwnd; - HDC hdc = ::BeginPaint(hwnd, &pdc.ps); - assign_to_opt_param(pPaintStruct, pdc.ps); - return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc); -} - -inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT -{ - return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc)); -} - -typedef unique_any unique_hgdiobj; -typedef unique_any unique_hpen; -typedef unique_any unique_hbrush; -typedef unique_any unique_hfont; -typedef unique_any unique_hbitmap; -typedef unique_any unique_hrgn; -typedef unique_any unique_hpalette; -typedef unique_any unique_hdc; -typedef unique_any unique_hicon; + typedef unique_any unique_hgdiobj; + typedef unique_any unique_hpen; + typedef unique_any unique_hbrush; + typedef unique_any unique_hfont; + typedef unique_any unique_hbitmap; + typedef unique_any unique_hrgn; + typedef unique_any unique_hpalette; + typedef unique_any unique_hdc; + typedef unique_any unique_hicon; #if !defined(NOMENUS) -typedef unique_any unique_hmenu; + typedef unique_any unique_hmenu; #endif // !defined(NOMENUS) #endif // __WIL_WINGDI_ #if (defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINGDI_STL -/// @endcond -typedef shared_any shared_hgdiobj; -typedef shared_any shared_hpen; -typedef shared_any shared_hbrush; -typedef shared_any shared_hfont; -typedef shared_any shared_hbitmap; -typedef shared_any shared_hrgn; -typedef shared_any shared_hpalette; -typedef shared_any shared_hdc; -typedef shared_any shared_hicon; + /// @endcond + typedef shared_any shared_hgdiobj; + typedef shared_any shared_hpen; + typedef shared_any shared_hbrush; + typedef shared_any shared_hfont; + typedef shared_any shared_hbitmap; + typedef shared_any shared_hrgn; + typedef shared_any shared_hpalette; + typedef shared_any shared_hdc; + typedef shared_any shared_hicon; #if !defined(NOMENUS) -typedef shared_any shared_hmenu; + typedef shared_any shared_hmenu; #endif // !defined(NOMENUS) -typedef weak_any weak_hgdiobj; -typedef weak_any weak_hpen; -typedef weak_any weak_hbrush; -typedef weak_any weak_hfont; -typedef weak_any weak_hbitmap; -typedef weak_any weak_hrgn; -typedef weak_any weak_hpalette; -typedef weak_any weak_hdc; -typedef weak_any weak_hicon; + typedef weak_any weak_hgdiobj; + typedef weak_any weak_hpen; + typedef weak_any weak_hbrush; + typedef weak_any weak_hfont; + typedef weak_any weak_hbitmap; + typedef weak_any weak_hrgn; + typedef weak_any weak_hpalette; + typedef weak_any weak_hdc; + typedef weak_any weak_hicon; #if !defined(NOMENUS) -typedef weak_any weak_hmenu; + typedef weak_any weak_hmenu; #endif // !defined(NOMENUS) #endif // __WIL_WINGDI_STL #if (defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WTSAPI -/// @endcond -template -using unique_wtsmem_ptr = - wistd::unique_ptr, function_deleter>; + /// @endcond + template + using unique_wtsmem_ptr = wistd::unique_ptr, + function_deleter>; #endif // __WIL_WTSAPI #if (defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE)) || defined(WIL_DOXYGEN) #define __WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE -typedef unique_any_handle_null unique_channel_handle; + typedef unique_any_handle_null unique_channel_handle; #endif // __WIL_WTSAPI_WTSVIRTUALCHANNELCLOSE -#if (defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WINSCARD_H_ -/// @endcond -typedef unique_any unique_scardctx; + /// @endcond + typedef unique_any unique_scardctx; #endif // __WIL_WINSCARD_H_ #if (defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WINSCARD_H_STL -/// @endcond -typedef shared_any shared_scardctx; -typedef weak_any weak_scardctx; + /// @endcond + typedef shared_any shared_scardctx; + typedef weak_any weak_scardctx; #endif // __WIL_WINSCARD_H_STL #if (defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__WINCRYPT_H__ -namespace details -{ - inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT + namespace details { - ::CertCloseStore(hCertStore, 0); - } - - inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) WI_NOEXCEPT - { - ::CryptReleaseContext(hCryptCtx, 0); - } -} // namespace details -/// @endcond - -struct cert_context_t - : details::unique_storage> -{ - // forward all base class constructors... - template - explicit cert_context_t(args_t&&... args) WI_NOEXCEPT : unique_storage(wistd::forward(args)...) - { - } - - /** A wrapper around CertEnumCertificatesInStore. - CertEnumCertificatesInStore takes ownership of its second parameter in an unclear fashion, - making it error-prone to use in combination with unique_cert_context. This wrapper helps - manage the resource correctly while ensuring the GetLastError state set by CertEnumCertificatesInStore. - is not lost. See MSDN for more information on `CertEnumCertificatesInStore`. - ~~~~ - void MyMethod(HCERTSTORE certStore) - { - wil::unique_cert_context enumCert; - while (enumCert.CertEnumCertificatesInStore(certStore)) + inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT { - UseTheCertToDoTheThing(enumCert); + ::CertCloseStore(hCertStore, 0); } - } - ~~~~ - @param certStore A handle of a certificate store. - @return 'true' if a certificate was enumerated by this call, false otherwise. - */ - bool CertEnumCertificatesInStore(HCERTSTORE certStore) WI_NOEXCEPT - { - reset(::CertEnumCertificatesInStore(certStore, release())); - return is_valid(); - } -}; -// Warning - ::CertEnumCertificatesInStore takes ownership of its parameter. Prefer the -// .CertEnumCertificatesInStore method of the unique_cert_context or else use .release -// when calling ::CertEnumCertificatesInStore directly. -typedef unique_any_t unique_cert_context; -typedef unique_any unique_cert_chain_context; -typedef unique_any unique_hcertstore; -typedef unique_any unique_hcryptprov; -typedef unique_any unique_hcryptkey; -typedef unique_any unique_hcrypthash; -typedef unique_any unique_hcryptmsg; + inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) + WI_NOEXCEPT + { + ::CryptReleaseContext(hCryptCtx, 0); + } + } // namespace details + /// @endcond + + struct cert_context_t + : details::unique_storage> + { + // forward all base class constructors... + template + explicit cert_context_t(args_t &&...args) WI_NOEXCEPT : unique_storage(wistd::forward(args)...) + { + } + + /** A wrapper around CertEnumCertificatesInStore. + CertEnumCertificatesInStore takes ownership of its second parameter in an unclear fashion, + making it error-prone to use in combination with unique_cert_context. This wrapper helps + manage the resource correctly while ensuring the GetLastError state set by CertEnumCertificatesInStore. + is not lost. See MSDN for more information on `CertEnumCertificatesInStore`. + ~~~~ + void MyMethod(HCERTSTORE certStore) + { + wil::unique_cert_context enumCert; + while (enumCert.CertEnumCertificatesInStore(certStore)) + { + UseTheCertToDoTheThing(enumCert); + } + } + ~~~~ + @param certStore A handle of a certificate store. + @return 'true' if a certificate was enumerated by this call, false otherwise. + */ + bool CertEnumCertificatesInStore(HCERTSTORE certStore) WI_NOEXCEPT + { + reset(::CertEnumCertificatesInStore(certStore, release())); + return is_valid(); + } + }; + + // Warning - ::CertEnumCertificatesInStore takes ownership of its parameter. Prefer the + // .CertEnumCertificatesInStore method of the unique_cert_context or else use .release + // when calling ::CertEnumCertificatesInStore directly. + typedef unique_any_t unique_cert_context; + typedef unique_any + unique_cert_chain_context; + typedef unique_any + unique_hcertstore; + typedef unique_any + unique_hcryptprov; + typedef unique_any unique_hcryptkey; + typedef unique_any unique_hcrypthash; + typedef unique_any unique_hcryptmsg; #endif // __WIL__WINCRYPT_H__ -#if (defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL__WINCRYPT_H__STL -/// @endcond -typedef shared_any shared_cert_context; -typedef shared_any shared_cert_chain_context; -typedef shared_any shared_hcertstore; -typedef shared_any shared_hcryptprov; -typedef shared_any shared_hcryptkey; -typedef shared_any shared_hcrypthash; -typedef shared_any shared_hcryptmsg; + /// @endcond + typedef shared_any shared_cert_context; + typedef shared_any shared_cert_chain_context; + typedef shared_any shared_hcertstore; + typedef shared_any shared_hcryptprov; + typedef shared_any shared_hcryptkey; + typedef shared_any shared_hcrypthash; + typedef shared_any shared_hcryptmsg; -typedef weak_any weak_cert_context; -typedef weak_any weak_cert_chain_context; -typedef weak_any weak_hcertstore; -typedef weak_any weak_hcryptprov; -typedef weak_any weak_hcryptkey; -typedef weak_any weak_hcrypthash; -typedef weak_any weak_hcryptmsg; + typedef weak_any weak_cert_context; + typedef weak_any weak_cert_chain_context; + typedef weak_any weak_hcertstore; + typedef weak_any weak_hcryptprov; + typedef weak_any weak_hcryptkey; + typedef weak_any weak_hcrypthash; + typedef weak_any weak_hcryptmsg; #endif // __WIL__WINCRYPT_H__STL -#if (defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_NCRYPT_H__ -/// @endcond -using ncrypt_deleter = function_deleter; + /// @endcond + using ncrypt_deleter = function_deleter; -template -using unique_ncrypt_ptr = wistd::unique_ptr, ncrypt_deleter>; + template + using unique_ncrypt_ptr = wistd::unique_ptr, ncrypt_deleter>; -typedef unique_any unique_ncrypt_prov; -typedef unique_any unique_ncrypt_key; -typedef unique_any unique_ncrypt_secret; + typedef unique_any unique_ncrypt_prov; + typedef unique_any unique_ncrypt_key; + typedef unique_any unique_ncrypt_secret; #endif // __WIL_NCRYPT_H__ #if (defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_NCRYPT_H_STL -/// @endcond -typedef shared_any shared_ncrypt_prov; -typedef shared_any shared_ncrypt_key; -typedef shared_any shared_ncrypt_secret; + /// @endcond + typedef shared_any shared_ncrypt_prov; + typedef shared_any shared_ncrypt_key; + typedef shared_any shared_ncrypt_secret; -typedef weak_any weak_ncrypt_prov; -typedef weak_any weak_ncrypt_key; -typedef weak_any weak_ncrypt_secret; + typedef weak_any weak_ncrypt_prov; + typedef weak_any weak_ncrypt_key; + typedef weak_any weak_ncrypt_secret; #endif // __WIL_NCRYPT_H_STL -#if (defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_BCRYPT_H__ -namespace details -{ - inline void __stdcall BCryptCloseAlgorithmProviderNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT + namespace details { - if (hAlgorithm) + inline void __stdcall BCryptCloseAlgorithmProviderNoFlags( + _Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT { - ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + if (hAlgorithm) + { + ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + } } - } -} // namespace details -/// @endcond + } // namespace details + /// @endcond -using bcrypt_deleter = function_deleter; + using bcrypt_deleter = function_deleter; -template -using unique_bcrypt_ptr = wistd::unique_ptr, bcrypt_deleter>; + template + using unique_bcrypt_ptr = wistd::unique_ptr, bcrypt_deleter>; -typedef unique_any unique_bcrypt_algorithm; -typedef unique_any unique_bcrypt_hash; -typedef unique_any unique_bcrypt_key; -typedef unique_any unique_bcrypt_secret; + typedef unique_any + unique_bcrypt_algorithm; + typedef unique_any unique_bcrypt_hash; + typedef unique_any unique_bcrypt_key; + typedef unique_any + unique_bcrypt_secret; #endif // __WIL_BCRYPT_H__ #if (defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_BCRYPT_H_STL -/// @endcond -typedef shared_any shared_bcrypt_algorithm; -typedef shared_any shared_bcrypt_hash; -typedef shared_any shared_bcrypt_key; -typedef shared_any shared_bcrypt_secret; + /// @endcond + typedef shared_any shared_bcrypt_algorithm; + typedef shared_any shared_bcrypt_hash; + typedef shared_any shared_bcrypt_key; + typedef shared_any shared_bcrypt_secret; -typedef weak_any weak_bcrypt_algorithm; -typedef weak_any weak_bcrypt_hash; -typedef weak_any weak_bcrypt_key; -typedef weak_any weak_bcrypt_secret; + typedef weak_any weak_bcrypt_algorithm; + typedef weak_any weak_bcrypt_hash; + typedef weak_any weak_bcrypt_key; + typedef weak_any weak_bcrypt_secret; #endif // __WIL_BCRYPT_H_STL #if (defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL__RPCNDR_H__ -/// @endcond + /// @endcond -//! Function deleter for use with pointers allocated by MIDL_user_allocate -using midl_deleter = function_deleter; + //! Function deleter for use with pointers allocated by MIDL_user_allocate + using midl_deleter = function_deleter; -//! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation -template -using unique_midl_ptr = wistd::unique_ptr, midl_deleter>; + //! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation + template + using unique_midl_ptr = wistd::unique_ptr, midl_deleter>; -//! Unique-ptr for strings allocated by MIDL_user_alloc -using unique_midl_string = unique_midl_ptr; + //! Unique-ptr for strings allocated by MIDL_user_alloc + using unique_midl_string = unique_midl_ptr; #ifndef WIL_NO_ANSI_STRINGS -using unique_midl_ansistring = unique_midl_ptr; + using unique_midl_ansistring = unique_midl_ptr; #endif -/// @cond -namespace details -{ - struct midl_allocator + /// @cond + namespace details { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + struct midl_allocator { - return ::MIDL_user_allocate(size); - } - }; + static _Ret_opt_bytecap_(size) void *allocate(size_t size) WI_NOEXCEPT + { + return ::MIDL_user_allocate(size); + } + }; - // Specialization to support construction of unique_midl_string instances - template <> - struct string_allocator : midl_allocator - { - }; + // Specialization to support construction of unique_midl_string instances + template <> struct string_allocator : midl_allocator + { + }; #ifndef WIL_NO_ANSI_STRINGS - template <> - struct string_allocator : midl_allocator - { - }; + template <> struct string_allocator : midl_allocator + { + }; #endif -} // namespace details + } // namespace details /// @endcond #endif // __WIL__RPCNDR_H__ #if (defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_OBJBASE_H_ -/// @endcond -using cotaskmem_deleter = function_deleter; + /// @endcond + using cotaskmem_deleter = function_deleter; -template -using unique_cotaskmem_ptr = wistd::unique_ptr, cotaskmem_deleter>; + template + using unique_cotaskmem_ptr = wistd::unique_ptr, cotaskmem_deleter>; -template -using unique_cotaskmem_array_ptr = unique_array_ptr; + template using unique_cotaskmem_array_ptr = unique_array_ptr; -/** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon -allocation failure. Use `wil::make_unique_cotaskmem_nothrow()` for resources returned from APIs that must satisfy a memory -allocation contract that requires the use of `CoTaskMemAlloc()` / `CoTaskMemFree()`. Use `wil::make_unique_nothrow()` when -`CoTaskMemAlloc()` is not required. + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may + not throw upon allocation failure. Use `wil::make_unique_cotaskmem_nothrow()` for resources returned from APIs that + must satisfy a memory allocation contract that requires the use of `CoTaskMemAlloc()` / `CoTaskMemFree()`. Use + `wil::make_unique_nothrow()` when `CoTaskMemAlloc()` is not required. -Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee -initialization. + Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee + initialization. -Note that `wil::make_unique_cotaskmem_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class -that may throw in its constructor. -@code -auto foo = wil::make_unique_cotaskmem_nothrow(); -if (foo) -{ -// initialize allocated Foo object as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(Args&&... args) -{ - unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(sizeof(T)))); - if (sp) + Note that `wil::make_unique_cotaskmem_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an + exception-based class that may throw in its constructor. + @code + auto foo = wil::make_unique_cotaskmem_nothrow(); + if (foo) { - // use placement new to initialize memory from the previous allocation - new (sp.get()) T(wistd::forward(args)...); + // initialize allocated Foo object as appropriate } - return sp; -} - -/** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that may not throw -upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem_nothrow(size); -if (foos) -{ -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow( - size_t size) -{ - typedef typename wistd::remove_extent::type E; - FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); - size_t allocSize = sizeof(E) * size; - unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(allocSize))); - if (sp) + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type + make_unique_cotaskmem_nothrow(Args &&...args) { - // use placement new to initialize memory from the previous allocation; - // note that array placement new cannot be used as the standard allows for operator new[] - // to consume overhead in the allocation for internal bookkeeping - for (auto& elem : make_range(static_cast(sp.get()), size)) + unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(sizeof(T)))); + if (sp) { - new (&elem) E(); + // use placement new to initialize memory from the previous allocation + new (sp.get()) T(wistd::forward(args)...); } + return sp; } - return sp; -} -/** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon -allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_cotaskmem_failfast(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(Args&&... args) -{ - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that + may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array + types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_ptr>::type + make_unique_cotaskmem_nothrow(size_t size) + { + typedef typename wistd::remove_extent::type E; + FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); + size_t allocSize = sizeof(E) * size; + unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(allocSize))); + if (sp) + { + // use placement new to initialize memory from the previous allocation; + // note that array placement new cannot be used as the standard allows for operator new[] + // to consume overhead in the allocation for internal bookkeeping + for (auto &elem : make_range(static_cast(sp.get()), size)) + { + new (&elem) E(); + } + } + return sp; + } -/** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast -upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem_failfast(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast( - size_t size) -{ - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must + fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types + for more details. + @code + auto foo = wil::make_unique_cotaskmem_failfast(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type + make_unique_cotaskmem_failfast(Args &&...args) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that + must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array + types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_ptr>::type + make_unique_cotaskmem_failfast(size_t size) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`. -See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_cotaskmem(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem(Args&&... args) -{ - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + @code + auto foo = wil::make_unique_cotaskmem(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem( + Args &&...args) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } -/** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`. -See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem(size_t size) -{ - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_ptr>::type + make_unique_cotaskmem(size_t size) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -typedef unique_any unique_cotaskmem; -typedef unique_any unique_cotaskmem_string; + typedef unique_any unique_cotaskmem; + typedef unique_any unique_cotaskmem_string; #ifndef WIL_NO_ANSI_STRINGS -typedef unique_any unique_cotaskmem_ansistring; + typedef unique_any unique_cotaskmem_ansistring; #endif // WIL_NO_ANSI_STRINGS -/// @cond -namespace details -{ - struct cotaskmem_allocator + /// @cond + namespace details { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + struct cotaskmem_allocator { - return ::CoTaskMemAlloc(size); - } - }; + static _Ret_opt_bytecap_(size) void *allocate(size_t size) WI_NOEXCEPT + { + return ::CoTaskMemAlloc(size); + } + }; - template <> - struct string_allocator : cotaskmem_allocator - { - }; + template <> struct string_allocator : cotaskmem_allocator + { + }; #ifndef WIL_NO_ANSI_STRINGS - template <> - struct string_allocator : cotaskmem_allocator - { - }; + template <> struct string_allocator : cotaskmem_allocator + { + }; #endif // WIL_NO_ANSI_STRINGS -} // namespace details -/// @endcond + } // namespace details + /// @endcond -inline auto make_cotaskmem_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_nothrow(source, length); -} + inline auto make_cotaskmem_string_nothrow(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } -inline auto make_cotaskmem_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) WI_NOEXCEPT -{ - return make_unique_string_failfast(source, length); -} + inline auto make_cotaskmem_string_failfast(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), + _In_z_) PCWSTR source, + size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } #ifdef WIL_ENABLE_EXCEPTIONS -inline auto make_cotaskmem_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) PCWSTR source, - size_t length = static_cast(-1)) -{ - return make_unique_string(source, length); -} + inline auto make_cotaskmem_string(_When_((source != nullptr) && length != static_cast(-1), + _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, + size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } #endif // WIL_ENABLE_EXCEPTIONS #endif // __WIL_OBJBASE_H_ #if (defined(__WIL_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_OBJBASE_H_STL -/// @endcond -typedef shared_any shared_cotaskmem; -typedef weak_any weak_cotaskmem; -typedef shared_any shared_cotaskmem_string; -typedef weak_any weak_cotaskmem_string; + /// @endcond + typedef shared_any shared_cotaskmem; + typedef weak_any weak_cotaskmem; + typedef shared_any shared_cotaskmem_string; + typedef weak_any weak_cotaskmem_string; #endif // __WIL_OBJBASE_H_STL -#if (defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_OBJBASE_AND_WINBASE_H_ -/// @endcond + /// @endcond -struct cotaskmem_secure_deleter -{ - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + struct cotaskmem_secure_deleter { - if (p) + template void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T *p) const { - IMalloc* malloc; - if (SUCCEEDED(::CoGetMalloc(1, &malloc))) + if (p) { - size_t const size = malloc->GetSize(p); - if (size != static_cast(-1)) + IMalloc *malloc; + if (SUCCEEDED(::CoGetMalloc(1, &malloc))) { - ::SecureZeroMemory(p, size); + size_t const size = malloc->GetSize(p); + if (size != static_cast(-1)) + { + ::SecureZeroMemory(p, size); + } + malloc->Release(); } - malloc->Release(); + ::CoTaskMemFree(p); } - ::CoTaskMemFree(p); } + }; + + template + using unique_cotaskmem_secure_ptr = + wistd::unique_ptr, cotaskmem_secure_deleter>; + + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that + may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array + types for more details. + @code + auto foo = wil::make_unique_cotaskmem_secure_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure_nothrow(Args &&...args) + { + return unique_cotaskmem_secure_ptr( + make_unique_cotaskmem_nothrow(wistd::forward(args)...).release()); } -}; -template -using unique_cotaskmem_secure_ptr = wistd::unique_ptr, cotaskmem_secure_deleter>; + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a + context that may not throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for + non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure_nothrow(size_t size) + { + return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(size).release()); + } -/** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that may not throw -upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_cotaskmem_secure_nothrow(); -if (foo) -{ -// initialize allocated Foo object as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow( - Args&&... args) -{ - return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(wistd::forward(args)...).release()); -} + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that + must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array + types for more details. + @code + auto foo = wil::make_unique_cotaskmem_secure_failfast(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure_failfast(Args &&...args) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } -/** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that may not -throw upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem_secure_nothrow(size); -if (foos) -{ -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow( - size_t size) -{ - return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(size).release()); -} - -/** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that must fail -fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_cotaskmem_secure_failfast(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast( - Args&&... args) -{ - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} - -/** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that must -fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more -details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem_secure_failfast(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast( - size_t size) -{ - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a + context that must fail fast upon allocation failure. See the overload of `wil::make_unique_cotaskmem_nothrow()` for + non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure_failfast(size_t size) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`. -See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -auto foo = wil::make_unique_cotaskmem_secure(); -// initialize allocated Foo object as appropriate -@endcode -*/ -template -inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(Args&&... args) -{ - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + @code + auto foo = wil::make_unique_cotaskmem_secure(); + // initialize allocated Foo object as appropriate + @endcode + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure(Args &&...args) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } -/** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`. -See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. -@code -const size_t size = 42; -auto foos = wil::make_unique_cotaskmem_secure(size); -for (auto& elem : wil::make_range(foos.get(), size)) -{ -// initialize allocated Foo objects as appropriate -} -@endcode -*/ -template -inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure( - size_t size) -{ - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + @code + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + @endcode + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, + unique_cotaskmem_secure_ptr>::type + make_unique_cotaskmem_secure(size_t size) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif // WIL_ENABLE_EXCEPTIONS -typedef unique_cotaskmem_secure_ptr unique_cotaskmem_string_secure; + typedef unique_cotaskmem_secure_ptr unique_cotaskmem_string_secure; -/** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation -failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string"); -if (str) -{ -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -} -~~~ -*/ -inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT -{ - return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release()); -} + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon + allocation failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more + details. + ~~~ + auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string"); + if (str) + { + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + } + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT + { + return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release()); + } -/** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation -failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_cotaskmem_string_secure_failfast(L"a string"); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -~~~ -*/ -inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT -{ - unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; -} + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon + allocation failure. See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more + details. + ~~~ + auto str = wil::make_cotaskmem_string_secure_failfast(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT + { + unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -/** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`. -See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. -~~~ -auto str = wil::make_cotaskmem_string_secure(L"a string"); -std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" -~~~ -*/ -inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source) -{ - unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; -} + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_cotaskmem_string_secure(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source) + { + unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } #endif #endif // __WIL_OBJBASE_AND_WINBASE_H_ -#if (defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_OLE2_H_ -/// @endcond -typedef unique_struct unique_stg_medium; -struct unique_hglobal_locked : public unique_any -{ - unique_hglobal_locked() = delete; - - explicit unique_hglobal_locked(HGLOBAL global) : unique_any(global) + /// @endcond + typedef unique_struct unique_stg_medium; + struct unique_hglobal_locked : public unique_any { - // GlobalLock returns a pointer to the associated global memory block and that's what callers care about. - m_globalMemory = GlobalLock(global); - if (!m_globalMemory) + unique_hglobal_locked() = delete; + + explicit unique_hglobal_locked(HGLOBAL global) + : unique_any(global) { - release(); + // GlobalLock returns a pointer to the associated global memory block and that's what callers care about. + m_globalMemory = GlobalLock(global); + if (!m_globalMemory) + { + release(); + } } - } - explicit unique_hglobal_locked(STGMEDIUM& medium) : unique_hglobal_locked(medium.hGlobal) + explicit unique_hglobal_locked(STGMEDIUM &medium) : unique_hglobal_locked(medium.hGlobal) + { + } + + WI_NODISCARD pointer get() const + { + return m_globalMemory; + } + + private: + pointer m_globalMemory; + }; + + //! A type that calls OleUninitialize on destruction (or reset()). + //! Use as a replacement for Windows::Foundation::Uninitialize. + using unique_oleuninitialize_call = unique_call; + + //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + _Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast() { + FAIL_FAST_IF_FAILED(::OleInitialize(nullptr)); + return unique_oleuninitialize_call(); } - WI_NODISCARD pointer get() const - { - return m_globalMemory; - } - -private: - pointer m_globalMemory; -}; - -//! A type that calls OleUninitialize on destruction (or reset()). -//! Use as a replacement for Windows::Foundation::Uninitialize. -using unique_oleuninitialize_call = unique_call; - -//! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts -//! Use as a replacement for Windows::Foundation::Initialize -_Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast() -{ - FAIL_FAST_IF_FAILED(::OleInitialize(nullptr)); - return unique_oleuninitialize_call(); -} - #ifdef WIL_ENABLE_EXCEPTIONS -//! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts -//! Use as a replacement for Windows::Foundation::Initialize -_Check_return_ inline unique_oleuninitialize_call OleInitialize() -{ - THROW_IF_FAILED(::OleInitialize(nullptr)); - return unique_oleuninitialize_call(); -} + //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + _Check_return_ inline unique_oleuninitialize_call OleInitialize() + { + THROW_IF_FAILED(::OleInitialize(nullptr)); + return unique_oleuninitialize_call(); + } #endif #endif // __WIL_OLE2_H_ #if (defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_COMMCTRL -/// @endcond -typedef unique_any unique_himagelist; + /// @endcond + typedef unique_any unique_himagelist; #endif // __WIL_INC_COMMCTRL -#if (defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_COMMCTRL_STL -/// @endcond -typedef shared_any shared_himagelist; -typedef weak_any weak_himagelist; + /// @endcond + typedef shared_any shared_himagelist; + typedef weak_any weak_himagelist; #endif // __WIL_INC_COMMCTRL_STL #if (defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_UXTHEME -/// @endcond -typedef unique_any unique_htheme; + /// @endcond + typedef unique_any unique_htheme; #endif // __WIL_INC_UXTHEME #pragma warning(push) #pragma warning(disable : 4995) -#if (defined(_INC_USERENV) && !defined(__WIL_INC_USERENV) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_INC_USERENV) && !defined(__WIL_INC_USERENV) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_USERENV -/// @endcond -typedef unique_any unique_environment_block; + /// @endcond + typedef unique_any + unique_environment_block; #endif // __WIL_INC_USERENV #pragma warning(pop) -#if (defined(__WINEVT_H__) && !defined(__WIL_INC_EVT_HANDLE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_EVENTLOGSERVICE) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(__WINEVT_H__) && !defined(__WIL_INC_EVT_HANDLE) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_EVENTLOGSERVICE) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_EVT_HANDLE -/// @endcond -typedef unique_any unique_evt_handle; + /// @endcond + typedef unique_any unique_evt_handle; #endif // __WIL_INC_EVT_HANDLE -#if (defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_HANDLE_H_WINSVC -/// @endcond -typedef unique_any unique_schandle; + /// @endcond + typedef unique_any unique_schandle; #endif // __WIL_HANDLE_H_WINSVC -#if (defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_HANDLE_H_WINSVC_STL -/// @endcond -typedef shared_any shared_schandle; -typedef weak_any weak_schandle; + /// @endcond + typedef shared_any shared_schandle; + typedef weak_any weak_schandle; #endif // __WIL_HANDLE_H_WINSVC_STL -#if (defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ + !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_STDIO -/// @endcond -typedef unique_any unique_pipe; -typedef unique_any unique_file; + /// @endcond + typedef unique_any unique_pipe; + typedef unique_any unique_file; #endif // __WIL_INC_STDIO #if (defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL__INC_STDIO_STL -/// @endcond -typedef shared_any shared_pipe; -typedef weak_any weak_pipe; -typedef shared_any shared_file; -typedef weak_any weak_file; + /// @endcond + typedef shared_any shared_pipe; + typedef weak_any weak_pipe; + typedef shared_any shared_file; + typedef weak_any weak_file; #endif // __WIL__INC_STDIO_STL #if (defined(_INC_LOCALE) && !defined(__WIL_INC_LOCALE) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_INC_LOCALE -/// @endcond -typedef unique_any<_locale_t, decltype(&::_free_locale), ::_free_locale> unique_locale; + /// @endcond + typedef unique_any<_locale_t, decltype(&::_free_locale), ::_free_locale> unique_locale; #endif // __WIL_INC_LOCALE #if (defined(__WIL_INC_LOCALE) && !defined(__WIL__INC_LOCALE_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL__INC_LOCALE_STL -/// @endcond -typedef shared_any shared_locale; -typedef weak_any weak_locale; + /// @endcond + typedef shared_any shared_locale; + typedef weak_any weak_locale; #endif // __WIL__INC_LOCALE_STL #if (defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_NTLSA_ -/// @endcond -typedef unique_any unique_hlsa; + /// @endcond + typedef unique_any unique_hlsa; -using lsa_freemem_deleter = function_deleter; + using lsa_freemem_deleter = function_deleter; -template -using unique_lsamem_ptr = wistd::unique_ptr, lsa_freemem_deleter>; + template + using unique_lsamem_ptr = wistd::unique_ptr, lsa_freemem_deleter>; #endif // _NTLSA_ #if (defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_NTLSA_STL -/// @endcond -typedef shared_any shared_hlsa; -typedef weak_any weak_hlsa; + /// @endcond + typedef shared_any shared_hlsa; + typedef weak_any weak_hlsa; #endif // _NTLSA_ #if (defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_LSALOOKUP_ -/// @endcond -typedef unique_any unique_hlsalookup; + /// @endcond + typedef unique_any unique_hlsalookup; -using lsalookup_freemem_deleter = function_deleter; + using lsalookup_freemem_deleter = function_deleter; -template -using unique_lsalookupmem_ptr = wistd::unique_ptr, lsalookup_freemem_deleter>; + template + using unique_lsalookupmem_ptr = + wistd::unique_ptr, lsalookup_freemem_deleter>; #endif // _LSALOOKUP_ #if (defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_LSALOOKUP_STL -/// @endcond -typedef shared_any shared_hlsalookup; -typedef weak_any weak_hlsalookup; + /// @endcond + typedef shared_any shared_hlsalookup; + typedef weak_any weak_hlsalookup; #endif // _LSALOOKUP_ -#if (defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_HANDLE_H_NTLSA_IFS_ -/// @endcond -using lsa_deleter = function_deleter; + /// @endcond + using lsa_deleter = function_deleter; -template -using unique_lsa_ptr = wistd::unique_ptr, lsa_deleter>; + template + using unique_lsa_ptr = wistd::unique_ptr, lsa_deleter>; #endif // __WIL_HANDLE_H_NTLSA_IFS_ -#if (defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WERAPI_H__ -/// @endcond -typedef unique_any unique_wer_report; + /// @endcond + typedef unique_any unique_wer_report; #endif -#if (defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_MIDLES_H__ -/// @endcond -typedef unique_any unique_rpc_pickle; + /// @endcond + typedef unique_any unique_rpc_pickle; #endif #if (defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_MIDLES_H_STL -/// @endcond -typedef shared_any shared_rpc_pickle; -typedef weak_any weak_rpc_pickle; + /// @endcond + typedef shared_any shared_rpc_pickle; + typedef weak_any weak_rpc_pickle; #endif -#if (defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_RPCDCE_H__ -namespace details -{ - inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding) + namespace details { - ::RpcBindingFree(&binding); - } + inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding) + { + ::RpcBindingFree(&binding); + } - inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR* bindingVector) - { - ::RpcBindingVectorFree(&bindingVector); - } + inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR *bindingVector) + { + ::RpcBindingVectorFree(&bindingVector); + } - inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr) - { - ::RpcStringFreeW(&wstr); - } -} // namespace details -/// @endcond + inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr) + { + ::RpcStringFreeW(&wstr); + } + } // namespace details + /// @endcond -typedef unique_any unique_rpc_binding; -typedef unique_any unique_rpc_binding_vector; -typedef unique_any unique_rpc_wstr; + typedef unique_any + unique_rpc_binding; + typedef unique_any + unique_rpc_binding_vector; + typedef unique_any unique_rpc_wstr; #endif #if (defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_RPCDCE_H_STL -/// @endcond -typedef shared_any shared_rpc_binding; -typedef weak_any weak_rpc_binding; -typedef shared_any shared_rpc_binding_vector; -typedef weak_any weak_rpc_binding_vector; -typedef shared_any shared_rpc_wstr; -typedef weak_any weak_rpc_wstr; + /// @endcond + typedef shared_any shared_rpc_binding; + typedef weak_any weak_rpc_binding; + typedef shared_any shared_rpc_binding_vector; + typedef weak_any weak_rpc_binding_vector; + typedef shared_any shared_rpc_wstr; + typedef weak_any weak_rpc_wstr; #endif -#if (defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WCMAPI_H_ -/// @endcond -using wcm_deleter = function_deleter; + /// @endcond + using wcm_deleter = function_deleter; -template -using unique_wcm_ptr = wistd::unique_ptr, wcm_deleter>; + template + using unique_wcm_ptr = wistd::unique_ptr, wcm_deleter>; #endif -#if (defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && \ + !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_NETIOAPI_H_ -/// @endcond -typedef unique_any unique_mib_iftable; + /// @endcond + typedef unique_any unique_mib_iftable; #endif #if (defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_NETIOAPI_H_STL -/// @endcond -typedef shared_any shared_mib_iftable; -typedef weak_any weak_mib_iftable; + /// @endcond + typedef shared_any shared_mib_iftable; + typedef weak_any weak_mib_iftable; #endif -#if (defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ +#if (defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WLAN_WLANAPI_H -/// @endcond -using wlan_deleter = function_deleter; + /// @endcond + using wlan_deleter = function_deleter; -template -using unique_wlan_ptr = wistd::unique_ptr, wlan_deleter>; + template + using unique_wlan_ptr = wistd::unique_ptr, wlan_deleter>; -/// @cond -namespace details -{ - inline void __stdcall CloseWlanHandle(_In_ HANDLE hClientHandle) + /// @cond + namespace details { - ::WlanCloseHandle(hClientHandle, nullptr); - } -} // namespace details -/// @endcond + inline void __stdcall CloseWlanHandle(_In_ HANDLE hClientHandle) + { + ::WlanCloseHandle(hClientHandle, nullptr); + } + } // namespace details + /// @endcond -typedef unique_any unique_wlan_handle; + typedef unique_any + unique_wlan_handle; #endif -#if (defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_WLAN_WLANAPI_H_STL -/// @endcond -typedef shared_any shared_wlan_handle; -typedef weak_any weak_wlan_handle; + /// @endcond + typedef shared_any shared_wlan_handle; + typedef weak_any weak_wlan_handle; #endif -#if (defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE)) || defined(WIL_DOXYGEN) +#if (defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_HPOWERNOTIFY_DEF_H_ -/// @endcond -typedef unique_any unique_hpowernotify; + /// @endcond + typedef unique_any + unique_hpowernotify; #endif #if (defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_PSID_DEF_H_ -/// @endcond -typedef unique_any unique_process_heap_psid; -typedef unique_any unique_any_psid; + /// @endcond + typedef unique_any unique_process_heap_psid; + typedef unique_any unique_any_psid; #if defined(_OBJBASE_H_) || defined(WIL_DOXYGEN) -typedef unique_any unique_cotaskmem_psid; + typedef unique_any unique_cotaskmem_psid; #endif #endif -#if (defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ +#if (defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_PROCESSTHREADSAPI_H_DESK_SYS -namespace details -{ - inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION* p) + namespace details { - if (p->hProcess) + inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION *p) { - CloseHandle(p->hProcess); - } + if (p->hProcess) + { + CloseHandle(p->hProcess); + } - if (p->hThread) - { - CloseHandle(p->hThread); + if (p->hThread) + { + CloseHandle(p->hThread); + } } - } -} // namespace details -/// @endcond + } // namespace details + /// @endcond -/** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods. -~~~ -unique_process_information process; -CreateProcessW(..., CREATE_SUSPENDED, ..., &process); -THROW_LAST_ERROR_IF(ResumeThread(process.hThread) == -1); -THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0); -~~~ -*/ -using unique_process_information = - unique_struct; + /** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods. + ~~~ + unique_process_information process; + CreateProcessW(..., CREATE_SUSPENDED, ..., &process); + THROW_LAST_ERROR_IF(ResumeThread(process.hThread) == -1); + THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0); + ~~~ + */ + using unique_process_information = unique_struct; #endif -#if (defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ +#if (defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && \ + WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL__PROCESSENV_ -/// @endcond -/** Manages lifecycle of an environment-strings block. -@code -wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() }; -const wchar_t *nextVar = env.get(); -while (nextVar && *nextVar) -{ - // consume 'nextVar' - nextVar += wcslen(nextVar) + 1; -} -@endcode -*/ -using unique_environstrings_ptr = - wistd::unique_ptr>; + /// @endcond + /** Manages lifecycle of an environment-strings block. + @code + wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() }; + const wchar_t *nextVar = env.get(); + while (nextVar && *nextVar) + { + // consume 'nextVar' + nextVar += wcslen(nextVar) + 1; + } + @endcode + */ + using unique_environstrings_ptr = + wistd::unique_ptr>; #ifndef WIL_NO_ANSI_STRINGS -//! ANSI equivalent to unique_environstrings_ptr; -using unique_environansistrings_ptr = - wistd::unique_ptr>; + //! ANSI equivalent to unique_environstrings_ptr; + using unique_environansistrings_ptr = + wistd::unique_ptr>; #endif #endif -#if (defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || defined(WIL_DOXYGEN) +#if (defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_APPMODEL_H_ -/// @endcond -typedef unique_any unique_package_info_reference; + /// @endcond + typedef unique_any + unique_package_info_reference; #if NTDDI_VERSION >= NTDDI_WIN10_CO -typedef unique_any unique_package_dependency_context; + typedef unique_any + unique_package_dependency_context; #endif // NTDDI_VERSION >= NTDDI_WIN10_CO #endif // __WIL_APPMODEL_H_ #if (defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_APPMODEL_H_STL -/// @endcond -typedef shared_any shared_package_info_reference; -typedef weak_any weak_package_info_reference; + /// @endcond + typedef shared_any shared_package_info_reference; + typedef weak_any weak_package_info_reference; #if NTDDI_VERSION >= NTDDI_WIN10_CO -typedef shared_any shared_package_dependency_context; -typedef weak_any weak_package_dependency_context; + typedef shared_any shared_package_dependency_context; + typedef weak_any weak_package_dependency_context; #endif // NTDDI_VERSION >= NTDDI_WIN10_CO #endif // __WIL_APPMODEL_H_STL #if (defined(MSIXDYNAMICDEPENDENCY_H) && !defined(__WIL_MSIXDYNAMICDEPENDENCY_H)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_MSIXDYNAMICDEPENDENCY_H -/// @endcond -typedef unique_any unique_mdd_package_dependency_context; + /// @endcond + typedef unique_any + unique_mdd_package_dependency_context; #endif // __WIL_MSIXDYNAMICDEPENDENCY_H -#if (defined(MSIXDYNAMICDEPENDENCY_H) && !defined(__WIL_MSIXDYNAMICDEPENDENCY_H_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(MSIXDYNAMICDEPENDENCY_H) && !defined(__WIL_MSIXDYNAMICDEPENDENCY_H_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_MSIXDYNAMICDEPENDENCY_H_STL -/// @endcond -typedef shared_any shared_mdd_package_dependency_context; -typedef weak_any weak_mdd_package_dependency_context; + /// @endcond + typedef shared_any shared_mdd_package_dependency_context; + typedef weak_any weak_mdd_package_dependency_context; #endif // __WIL_MSIXDYNAMICDEPENDENCY_H_STL #if (defined(_APISETLIBLOADER_) && !defined(__WIL_APISETLIBLOADER_)) || defined(WIL_DOXYGEN) @@ -6272,1227 +6416,1230 @@ typedef weak_any weak_mdd_package_depende #define __WIL_APISETLIBLOADER_ /// @endcond #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -typedef unique_any unique_dll_directory_cookie; + typedef unique_any + unique_dll_directory_cookie; #endif #endif // __WIL_APISETLIBLOADER_ -#if (defined(_APISETLIBLOADER_) && !defined(__WIL_APISETLIBLOADER_STL) && defined(WIL_RESOURCE_STL)) || defined(WIL_DOXYGEN) +#if (defined(_APISETLIBLOADER_) && !defined(__WIL_APISETLIBLOADER_STL) && defined(WIL_RESOURCE_STL)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_APISETLIBLOADER_STL /// @endcond #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -typedef shared_any shared_dll_directory_cookie; -typedef weak_any weak_dll_directory_cookie; + typedef shared_any shared_dll_directory_cookie; + typedef weak_any weak_dll_directory_cookie; #endif #endif // __WIL_APISETLIBLOADER_STL #if (defined(WDFAPI) && !defined(__WIL_WDFAPI)) || defined(WIL_DOXYGEN) /// @cond #define __WIL_WDFAPI -namespace details -{ + namespace details + { + template + using wdf_object_resource_policy = + resource_policy; + } + /// @endcond + template - using wdf_object_resource_policy = resource_policy; -} -/// @endcond + using unique_wdf_any = unique_any_t>>; -template -using unique_wdf_any = unique_any_t>>; + using unique_wdf_object = unique_wdf_any; + using unique_wdf_queue = unique_wdf_any; -using unique_wdf_object = unique_wdf_any; -using unique_wdf_queue = unique_wdf_any; + using unique_wdf_timer = unique_wdf_any; + using unique_wdf_work_item = unique_wdf_any; -using unique_wdf_timer = unique_wdf_any; -using unique_wdf_work_item = unique_wdf_any; + using unique_wdf_memory = unique_wdf_any; -using unique_wdf_memory = unique_wdf_any; + using unique_wdf_dma_enabler = unique_wdf_any; + using unique_wdf_dma_transaction = unique_wdf_any; + using unique_wdf_common_buffer = unique_wdf_any; -using unique_wdf_dma_enabler = unique_wdf_any; -using unique_wdf_dma_transaction = unique_wdf_any; -using unique_wdf_common_buffer = unique_wdf_any; + using unique_wdf_key = unique_wdf_any; + using unique_wdf_string = unique_wdf_any; + using unique_wdf_collection = unique_wdf_any; -using unique_wdf_key = unique_wdf_any; -using unique_wdf_string = unique_wdf_any; -using unique_wdf_collection = unique_wdf_any; - -using wdf_wait_lock_release_scope_exit = - unique_any; + using wdf_wait_lock_release_scope_exit = + unique_any; #if defined(WIL_KERNEL_MODE) -using unique_wdf_device_init = unique_any; + using unique_wdf_device_init = unique_any; #endif -WI_NODISCARD inline _IRQL_requires_max_(PASSIVE_LEVEL) -_Acquires_lock_(lock) -wdf_wait_lock_release_scope_exit acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT -{ - ::WdfWaitLockAcquire(lock, nullptr); - return wdf_wait_lock_release_scope_exit(lock); -} - -WI_NODISCARD inline _IRQL_requires_max_(APC_LEVEL) -_When_(return, _Acquires_lock_(lock)) -wdf_wait_lock_release_scope_exit try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT -{ - LONGLONG timeout = 0; - NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout); - if (status == STATUS_SUCCESS) + WI_NODISCARD inline _IRQL_requires_max_(PASSIVE_LEVEL) _Acquires_lock_(lock) wdf_wait_lock_release_scope_exit + acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT { + ::WdfWaitLockAcquire(lock, nullptr); return wdf_wait_lock_release_scope_exit(lock); } - else + + WI_NODISCARD inline _IRQL_requires_max_(APC_LEVEL) + _When_(return, _Acquires_lock_(lock)) wdf_wait_lock_release_scope_exit + try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT { - return wdf_wait_lock_release_scope_exit(); - } -} - -using wdf_spin_lock_release_scope_exit = - unique_any; - -WI_NODISCARD inline _IRQL_requires_max_(DISPATCH_LEVEL) -_IRQL_raises_(DISPATCH_LEVEL) -_Acquires_lock_(lock) -wdf_spin_lock_release_scope_exit acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT -{ - ::WdfSpinLockAcquire(lock); - return wdf_spin_lock_release_scope_exit(lock); -} - -/// @cond -namespace details -{ - template - using unique_wdf_lock_storage = unique_storage>; - - class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage - { - using wdf_lock_storage_t = unique_wdf_lock_storage; - - public: - using pointer = wdf_lock_storage_t::pointer; - - // Forward all base class constructors, but have it be explicit. - template - explicit unique_wdf_spin_lock_storage(args_t&&... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) + LONGLONG timeout = 0; + NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout); + if (status == STATUS_SUCCESS) { + return wdf_wait_lock_release_scope_exit(lock); } - - NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) + else { - return ::WdfSpinLockCreate(attributes, out_param(*this)); + return wdf_wait_lock_release_scope_exit(); } - - WI_NODISCARD - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_raises_(DISPATCH_LEVEL) - wdf_spin_lock_release_scope_exit acquire() WI_NOEXCEPT - { - return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get()); - } - }; - - class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage - { - using wdf_lock_storage_t = unique_wdf_lock_storage; - - public: - using pointer = wdf_lock_storage_t::pointer; - - // Forward all base class constructors, but have it be explicit. - template - explicit unique_wdf_wait_lock_storage(args_t&&... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) - { - } - - NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) - { - return ::WdfWaitLockCreate(attributes, out_param(*this)); - } - - WI_NODISCARD - _IRQL_requires_max_(PASSIVE_LEVEL) - wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT - { - return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get()); - } - - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT - { - return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get()); - } - }; -} // namespace details -/// @endcond - -using unique_wdf_wait_lock = unique_any_t; -using unique_wdf_spin_lock = unique_any_t; - -//! unique_wdf_object_reference is a RAII type for managing WDF object references acquired using -//! the WdfObjectReference* family of APIs. The behavior of this class is exactly identical to -//! wil::unique_any but a few methods have some WDF-object-reference-specific enhancements. -//! -//! * The constructor takes not only a WDFOBJECT-compatible type or a wil::unique_wdf_any, but -//! optionally also a tag with which the reference was acquired. -//! * A get_tag() method is provided to retrieve the tag. -//! * reset() is similar to the constructor in that it also optionally takes a tag. -//! * release() optionally takes an out-param that returns the tag. -//! -//! These subtle differences make it impossible to reuse the wil::unique_any_t template for its implementation. -template -class unique_wdf_object_reference -{ -public: - unique_wdf_object_reference() WI_NOEXCEPT = default; - - //! Wrap a WDF object reference that has already been acquired into this RAII type. If you - //! want to acquire a new reference instead, use WI_WdfObjectReferenceIncrement. - explicit unique_wdf_object_reference(wdf_object_t wdfObject, void* tag = nullptr) WI_NOEXCEPT : m_wdfObject(wdfObject), m_tag(tag) - { } - //! This is similar to the constructor that takes a raw WDF handle but is enlightened to - //! take a const-ref to a wil::unique_wdf_any<> instead, obviating the need to call .get() - //! on it. As with the other constructor, the expectation is that the raw reference has - //! already been acquired and ownership is being transferred into this RAII object. - explicit unique_wdf_object_reference(const wil::unique_wdf_any& wdfObject, void* tag = nullptr) WI_NOEXCEPT - : unique_wdf_object_reference(wdfObject.get(), tag) + using wdf_spin_lock_release_scope_exit = + unique_any; + + WI_NODISCARD inline _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL) + _Acquires_lock_(lock) wdf_spin_lock_release_scope_exit acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT { + ::WdfSpinLockAcquire(lock); + return wdf_spin_lock_release_scope_exit(lock); } - unique_wdf_object_reference(const unique_wdf_object_reference&) = delete; - unique_wdf_object_reference& operator=(const unique_wdf_object_reference&) = delete; - - unique_wdf_object_reference(unique_wdf_object_reference&& other) : m_wdfObject(other.m_wdfObject), m_tag(other.m_tag) + /// @cond + namespace details { - other.m_wdfObject = WDF_NO_HANDLE; - other.m_tag = nullptr; - } + template + using unique_wdf_lock_storage = unique_storage>; - unique_wdf_object_reference& operator=(unique_wdf_object_reference&& other) - { - if (this != wistd::addressof(other)) + class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage + { + using wdf_lock_storage_t = unique_wdf_lock_storage; + + public: + using pointer = wdf_lock_storage_t::pointer; + + // Forward all base class constructors, but have it be explicit. + template + explicit unique_wdf_spin_lock_storage(args_t &&...args) WI_NOEXCEPT + : wdf_lock_storage_t(wistd::forward(args)...) + { + } + + NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES *attributes = WDF_NO_OBJECT_ATTRIBUTES) + { + return ::WdfSpinLockCreate(attributes, out_param(*this)); + } + + WI_NODISCARD + _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_raises_(DISPATCH_LEVEL) wdf_spin_lock_release_scope_exit + acquire() WI_NOEXCEPT + { + return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get()); + } + }; + + class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage + { + using wdf_lock_storage_t = unique_wdf_lock_storage; + + public: + using pointer = wdf_lock_storage_t::pointer; + + // Forward all base class constructors, but have it be explicit. + template + explicit unique_wdf_wait_lock_storage(args_t &&...args) WI_NOEXCEPT + : wdf_lock_storage_t(wistd::forward(args)...) + { + } + + NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES *attributes = WDF_NO_OBJECT_ATTRIBUTES) + { + return ::WdfWaitLockCreate(attributes, out_param(*this)); + } + + WI_NODISCARD + _IRQL_requires_max_(PASSIVE_LEVEL) wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT + { + return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get()); + } + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT + { + return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get()); + } + }; + } // namespace details + /// @endcond + + using unique_wdf_wait_lock = unique_any_t; + using unique_wdf_spin_lock = unique_any_t; + + //! unique_wdf_object_reference is a RAII type for managing WDF object references acquired using + //! the WdfObjectReference* family of APIs. The behavior of this class is exactly identical to + //! wil::unique_any but a few methods have some WDF-object-reference-specific enhancements. + //! + //! * The constructor takes not only a WDFOBJECT-compatible type or a wil::unique_wdf_any, but + //! optionally also a tag with which the reference was acquired. + //! * A get_tag() method is provided to retrieve the tag. + //! * reset() is similar to the constructor in that it also optionally takes a tag. + //! * release() optionally takes an out-param that returns the tag. + //! + //! These subtle differences make it impossible to reuse the wil::unique_any_t template for its implementation. + template class unique_wdf_object_reference + { + public: + unique_wdf_object_reference() WI_NOEXCEPT = default; + + //! Wrap a WDF object reference that has already been acquired into this RAII type. If you + //! want to acquire a new reference instead, use WI_WdfObjectReferenceIncrement. + explicit unique_wdf_object_reference(wdf_object_t wdfObject, void *tag = nullptr) WI_NOEXCEPT + : m_wdfObject(wdfObject), + m_tag(tag) + { + } + + //! This is similar to the constructor that takes a raw WDF handle but is enlightened to + //! take a const-ref to a wil::unique_wdf_any<> instead, obviating the need to call .get() + //! on it. As with the other constructor, the expectation is that the raw reference has + //! already been acquired and ownership is being transferred into this RAII object. + explicit unique_wdf_object_reference(const wil::unique_wdf_any &wdfObject, + void *tag = nullptr) WI_NOEXCEPT + : unique_wdf_object_reference(wdfObject.get(), tag) + { + } + + unique_wdf_object_reference(const unique_wdf_object_reference &) = delete; + unique_wdf_object_reference &operator=(const unique_wdf_object_reference &) = delete; + + unique_wdf_object_reference(unique_wdf_object_reference &&other) + : m_wdfObject(other.m_wdfObject), m_tag(other.m_tag) { - reset(other.m_wdfObject, other.m_tag); other.m_wdfObject = WDF_NO_HANDLE; other.m_tag = nullptr; } - return *this; - } - - ~unique_wdf_object_reference() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_wdfObject != WDF_NO_HANDLE; - } - - WI_NODISCARD wdf_object_t get() const WI_NOEXCEPT - { - return m_wdfObject; - } - - WI_NODISCARD void* get_tag() const WI_NOEXCEPT - { - return m_tag; - } - - //! Replaces the current instance (releasing it if it exists) with a new WDF object - //! reference that has already been acquired by the caller. - void reset(wdf_object_t wdfObject = WDF_NO_HANDLE, void* tag = nullptr) WI_NOEXCEPT - { - if (m_wdfObject != WDF_NO_HANDLE) + unique_wdf_object_reference &operator=(unique_wdf_object_reference &&other) { - // We don't use WdfObjectDereferenceActual because there is no way to provide the - // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to - // worry about where it was released, only where it was acquired. - WdfObjectDereferenceWithTag(m_wdfObject, m_tag); + if (this != wistd::addressof(other)) + { + reset(other.m_wdfObject, other.m_tag); + other.m_wdfObject = WDF_NO_HANDLE; + other.m_tag = nullptr; + } + + return *this; } - m_wdfObject = wdfObject; - m_tag = tag; - } - - void reset(const wil::unique_wdf_any& wdfObject, void* tag = nullptr) WI_NOEXCEPT - { - reset(wdfObject.get(), tag); - } - - wdf_object_t release(_Outptr_opt_ void** tag = nullptr) WI_NOEXCEPT - { - const auto wdfObject = m_wdfObject; - wil::assign_to_opt_param(tag, m_tag); - m_wdfObject = WDF_NO_HANDLE; - m_tag = nullptr; - return wdfObject; - } - - void swap(unique_wdf_object_reference& other) WI_NOEXCEPT - { - wistd::swap_wil(m_wdfObject, other.m_wdfObject); - wistd::swap_wil(m_tag, other.m_tag); - } - - //! Drops the current reference if any, and returns a pointer to a WDF handle which can - //! receive a newly referenced WDF handle. The tag is assumed to be nullptr. If a different - //! tag needs to be used, a temporary variable will need to be used to receive the WDF - //! handle and a unique_wdf_object_reference will need to be constructed with it. - //! - //! The quintessential use-case for this method is WdfIoQueueFindRequest. - wdf_object_t* put() WI_NOEXCEPT - { - reset(); - return &m_wdfObject; - } - - wdf_object_t* operator&() WI_NOEXCEPT - { - return put(); - } - -private: - wdf_object_t m_wdfObject = WDF_NO_HANDLE; - void* m_tag = nullptr; -}; - -// Increment the ref-count on a WDF object and return a unique_wdf_object_reference for it. Use -// WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this -// function only if the call-site source location is obtained from elsewhere (i.e., plumbed -// through other abstractions). -template -WI_NODISCARD inline unique_wdf_object_reference wdf_object_reference_increment( - wdf_object_t wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT -{ - // Parameter is incorrectly marked as non-const, so the const-cast is required. - ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast(fileName)); - return unique_wdf_object_reference{wdfObject, tag}; -} - -template -WI_NODISCARD inline unique_wdf_object_reference wdf_object_reference_increment( - const wil::unique_wdf_any& wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT -{ - return wdf_object_reference_increment(wdfObject.get(), tag, lineNumber, fileName); -} - -// A macro so that we can capture __LINE__ and __FILE__. -#define WI_WdfObjectReferenceIncrement(wdfObject, tag) wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__) - -//! wdf_request_completer is a unique_any-like RAII class for managing completion of a -//! WDFREQUEST. On destruction or explicit reset() it completes the WDFREQUEST with parameters -//! (status, information, priority boost) previously set using methods on this class. -//! -//! This class does not use the unique_any_t template primarily because the release() and put() -//! methods need to return a WDFREQUEST/WDFREQUEST*, as opposed to the internal storage type. -class wdf_request_completer -{ -public: - explicit wdf_request_completer(WDFREQUEST wdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT : m_wdfRequest(wdfRequest) - { - } - - wdf_request_completer(const wdf_request_completer&) = delete; - wdf_request_completer& operator=(const wdf_request_completer&) = delete; - - wdf_request_completer(wdf_request_completer&& other) WI_NOEXCEPT : m_wdfRequest(other.m_wdfRequest), - m_status(other.m_status), - m_information(other.m_information), -#if defined(WIL_KERNEL_MODE) - m_priorityBoost(other.m_priorityBoost), -#endif - m_completionFlags(other.m_completionFlags) - { - clear_state(other); - } - - wdf_request_completer& operator=(wdf_request_completer&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + ~unique_wdf_object_reference() WI_NOEXCEPT { reset(); - m_wdfRequest = other.m_wdfRequest; - m_status = other.m_status; - m_information = other.m_information; + } + + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return m_wdfObject != WDF_NO_HANDLE; + } + + WI_NODISCARD wdf_object_t get() const WI_NOEXCEPT + { + return m_wdfObject; + } + + WI_NODISCARD void *get_tag() const WI_NOEXCEPT + { + return m_tag; + } + + //! Replaces the current instance (releasing it if it exists) with a new WDF object + //! reference that has already been acquired by the caller. + void reset(wdf_object_t wdfObject = WDF_NO_HANDLE, void *tag = nullptr) WI_NOEXCEPT + { + if (m_wdfObject != WDF_NO_HANDLE) + { + // We don't use WdfObjectDereferenceActual because there is no way to provide the + // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to + // worry about where it was released, only where it was acquired. + WdfObjectDereferenceWithTag(m_wdfObject, m_tag); + } + + m_wdfObject = wdfObject; + m_tag = tag; + } + + void reset(const wil::unique_wdf_any &wdfObject, void *tag = nullptr) WI_NOEXCEPT + { + reset(wdfObject.get(), tag); + } + + wdf_object_t release(_Outptr_opt_ void **tag = nullptr) WI_NOEXCEPT + { + const auto wdfObject = m_wdfObject; + wil::assign_to_opt_param(tag, m_tag); + m_wdfObject = WDF_NO_HANDLE; + m_tag = nullptr; + return wdfObject; + } + + void swap(unique_wdf_object_reference &other) WI_NOEXCEPT + { + wistd::swap_wil(m_wdfObject, other.m_wdfObject); + wistd::swap_wil(m_tag, other.m_tag); + } + + //! Drops the current reference if any, and returns a pointer to a WDF handle which can + //! receive a newly referenced WDF handle. The tag is assumed to be nullptr. If a different + //! tag needs to be used, a temporary variable will need to be used to receive the WDF + //! handle and a unique_wdf_object_reference will need to be constructed with it. + //! + //! The quintessential use-case for this method is WdfIoQueueFindRequest. + wdf_object_t *put() WI_NOEXCEPT + { + reset(); + return &m_wdfObject; + } + + wdf_object_t *operator&() WI_NOEXCEPT + { + return put(); + } + + private: + wdf_object_t m_wdfObject = WDF_NO_HANDLE; + void *m_tag = nullptr; + }; + + // Increment the ref-count on a WDF object and return a unique_wdf_object_reference for it. Use + // WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this + // function only if the call-site source location is obtained from elsewhere (i.e., plumbed + // through other abstractions). + template + WI_NODISCARD inline unique_wdf_object_reference wdf_object_reference_increment( + wdf_object_t wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT + { + // Parameter is incorrectly marked as non-const, so the const-cast is required. + ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast(fileName)); + return unique_wdf_object_reference{wdfObject, tag}; + } + + template + WI_NODISCARD inline unique_wdf_object_reference wdf_object_reference_increment( + const wil::unique_wdf_any &wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT + { + return wdf_object_reference_increment(wdfObject.get(), tag, lineNumber, fileName); + } + +// A macro so that we can capture __LINE__ and __FILE__. +#define WI_WdfObjectReferenceIncrement(wdfObject, tag) \ + wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__) + + //! wdf_request_completer is a unique_any-like RAII class for managing completion of a + //! WDFREQUEST. On destruction or explicit reset() it completes the WDFREQUEST with parameters + //! (status, information, priority boost) previously set using methods on this class. + //! + //! This class does not use the unique_any_t template primarily because the release() and put() + //! methods need to return a WDFREQUEST/WDFREQUEST*, as opposed to the internal storage type. + class wdf_request_completer + { + public: + explicit wdf_request_completer(WDFREQUEST wdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT : m_wdfRequest(wdfRequest) + { + } + + wdf_request_completer(const wdf_request_completer &) = delete; + wdf_request_completer &operator=(const wdf_request_completer &) = delete; + + wdf_request_completer(wdf_request_completer &&other) WI_NOEXCEPT : m_wdfRequest(other.m_wdfRequest), + m_status(other.m_status), + m_information(other.m_information), #if defined(WIL_KERNEL_MODE) - m_priorityBoost = other.m_priorityBoost; + m_priorityBoost(other.m_priorityBoost), #endif - m_completionFlags = other.m_completionFlags; + m_completionFlags(other.m_completionFlags) + { clear_state(other); } - return *this; - } - - ~wdf_request_completer() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD WDFREQUEST get() const WI_NOEXCEPT - { - return m_wdfRequest; - } - - //! Set the NTSTATUS value with with the WDFREQUEST will be completed when the RAII object - //! goes out of scope or .reset() is called explicitly. Calling this method does *not* - //! complete the request right away. No effect if this object currently does not have - //! ownership of a WDFREQUEST. The expected usage pattern is that set_status() is called - //! only after ownership of a WDFREQUEST is transferred to this object. - void set_status(NTSTATUS status) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_status = status; - } - - //! Set the IO_STATUS_BLOCK.Information value with which the WDFREQUEST will be completed. - //! Note that the Information value is not stored directly in the WDFREQUEST using - //! WdfRequestSetInformation. It is only used at the time of completion. No effect if this - //! object currently does not have ownership of a WDFREQUEST. The expected usage pattern is - //! that set_information() is called only after ownership of a WDFREQUEST is transferred to - //! this object. - void set_information(ULONG_PTR information) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_completionFlags.informationSet = 1; - m_information = information; - } - -#if defined(WIL_KERNEL_MODE) - //! Set the priority boost with which the WDFREQUEST will be completed. If this method is - //! called, the WDFREQUEST will eventually be completed with - //! WdfRequestCompleteWithPriorityBoost. No effect if this object currently does not have - //! ownership of a WDFREQUEST. The expected usage pattern is that set_priority_boost() is - //! called only after ownership of a WDFREQUEST is transferred to this object. - void set_priority_boost(CCHAR priorityBoost) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_completionFlags.priorityBoostSet = 1; - m_priorityBoost = priorityBoost; - } -#endif - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_wdfRequest != WDF_NO_HANDLE; - } - - WDFREQUEST* put() WI_NOEXCEPT - { - reset(); - return &m_wdfRequest; - } - - WDFREQUEST* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Relinquishes completion responsibility for the WDFREQUEST. Note that any state - //! (information, priority boost, status) set on this object is lost. This design choice was - //! made because it is atypical to set an information or priority boost value upfront; they - //! are typically set at the point where the request is going to be completed. Hence a - //! use-case wherein release() is called will typically not have set an information or - //! priority boost. - WDFREQUEST release() WI_NOEXCEPT - { - const auto wdfRequest = m_wdfRequest; - clear_state(*this); - return wdfRequest; - } - - void swap(wdf_request_completer& other) WI_NOEXCEPT - { - wistd::swap_wil(m_wdfRequest, other.m_wdfRequest); - wistd::swap_wil(m_information, other.m_information); - wistd::swap_wil(m_status, other.m_status); -#if defined(WIL_KERNEL_MODE) - wistd::swap_wil(m_priorityBoost, other.m_priorityBoost); -#endif - wistd::swap_wil(m_completionFlags, other.m_completionFlags); - } - - void reset(WDFREQUEST newWdfRequest = WDF_NO_HANDLE) - { - if (m_wdfRequest != WDF_NO_HANDLE) + wdf_request_completer &operator=(wdf_request_completer &&other) WI_NOEXCEPT { - // We try to match the usage patterns that the driver would have typically used in the - // various scenarios. For instance, if the driver has set the information field, we'll - // call WdfRequestCompleteWithInformation instead of calling WdfRequestSetInformation - // followed by WdfRequestComplete. - + if (this != wistd::addressof(other)) + { + reset(); + m_wdfRequest = other.m_wdfRequest; + m_status = other.m_status; + m_information = other.m_information; #if defined(WIL_KERNEL_MODE) - if (m_completionFlags.priorityBoostSet) - { - if (m_completionFlags.informationSet) - { - WdfRequestSetInformation(m_wdfRequest, m_information); - } - - WdfRequestCompleteWithPriorityBoost(m_wdfRequest, m_status, m_priorityBoost); - } - else + m_priorityBoost = other.m_priorityBoost; #endif - if (m_completionFlags.informationSet) - { - WdfRequestCompleteWithInformation(m_wdfRequest, m_status, m_information); - } - else - { - WdfRequestComplete(m_wdfRequest, m_status); + m_completionFlags = other.m_completionFlags; + clear_state(other); } + + return *this; } - // We call clear_state unconditionally just in case some parameters (status, - // information, etc.) were set prior to attaching a WDFREQUEST to this object. Those - // parameters are not considered relevant to the WDFREQUEST being attached to this - // object now. - clear_state(*this, newWdfRequest); - } + ~wdf_request_completer() WI_NOEXCEPT + { + reset(); + } + + WI_NODISCARD WDFREQUEST get() const WI_NOEXCEPT + { + return m_wdfRequest; + } + + //! Set the NTSTATUS value with with the WDFREQUEST will be completed when the RAII object + //! goes out of scope or .reset() is called explicitly. Calling this method does *not* + //! complete the request right away. No effect if this object currently does not have + //! ownership of a WDFREQUEST. The expected usage pattern is that set_status() is called + //! only after ownership of a WDFREQUEST is transferred to this object. + void set_status(NTSTATUS status) WI_NOEXCEPT + { + // The contract is that this method has no effect if we currently do not have a + // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is + // attached, not by explicitly checking for that condition here. + + m_status = status; + } + + //! Set the IO_STATUS_BLOCK.Information value with which the WDFREQUEST will be completed. + //! Note that the Information value is not stored directly in the WDFREQUEST using + //! WdfRequestSetInformation. It is only used at the time of completion. No effect if this + //! object currently does not have ownership of a WDFREQUEST. The expected usage pattern is + //! that set_information() is called only after ownership of a WDFREQUEST is transferred to + //! this object. + void set_information(ULONG_PTR information) WI_NOEXCEPT + { + // The contract is that this method has no effect if we currently do not have a + // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is + // attached, not by explicitly checking for that condition here. + + m_completionFlags.informationSet = 1; + m_information = information; + } -private: - static void clear_state(wdf_request_completer& completer, WDFREQUEST newWdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT - { - completer.m_wdfRequest = newWdfRequest; - completer.m_status = STATUS_UNSUCCESSFUL; - completer.m_information = 0; #if defined(WIL_KERNEL_MODE) - completer.m_priorityBoost = 0; + //! Set the priority boost with which the WDFREQUEST will be completed. If this method is + //! called, the WDFREQUEST will eventually be completed with + //! WdfRequestCompleteWithPriorityBoost. No effect if this object currently does not have + //! ownership of a WDFREQUEST. The expected usage pattern is that set_priority_boost() is + //! called only after ownership of a WDFREQUEST is transferred to this object. + void set_priority_boost(CCHAR priorityBoost) WI_NOEXCEPT + { + // The contract is that this method has no effect if we currently do not have a + // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is + // attached, not by explicitly checking for that condition here. + + m_completionFlags.priorityBoostSet = 1; + m_priorityBoost = priorityBoost; + } #endif - completer.m_completionFlags = {}; - } - // Members are ordered in decreasing size to minimize padding. + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return m_wdfRequest != WDF_NO_HANDLE; + } - WDFREQUEST m_wdfRequest = WDF_NO_HANDLE; + WDFREQUEST *put() WI_NOEXCEPT + { + reset(); + return &m_wdfRequest; + } - // This will not be used unless m_completionFlags.informationSet is set. - ULONG_PTR m_information = 0; + WDFREQUEST *operator&() WI_NOEXCEPT + { + return put(); + } - // There is no reasonably default NTSTATUS value. Callers are expected to explicitly set a - // status value at the point where it is decided that the request needs to be completed. - NTSTATUS m_status = STATUS_UNSUCCESSFUL; + //! Relinquishes completion responsibility for the WDFREQUEST. Note that any state + //! (information, priority boost, status) set on this object is lost. This design choice was + //! made because it is atypical to set an information or priority boost value upfront; they + //! are typically set at the point where the request is going to be completed. Hence a + //! use-case wherein release() is called will typically not have set an information or + //! priority boost. + WDFREQUEST release() WI_NOEXCEPT + { + const auto wdfRequest = m_wdfRequest; + clear_state(*this); + return wdfRequest; + } + + void swap(wdf_request_completer &other) WI_NOEXCEPT + { + wistd::swap_wil(m_wdfRequest, other.m_wdfRequest); + wistd::swap_wil(m_information, other.m_information); + wistd::swap_wil(m_status, other.m_status); +#if defined(WIL_KERNEL_MODE) + wistd::swap_wil(m_priorityBoost, other.m_priorityBoost); +#endif + wistd::swap_wil(m_completionFlags, other.m_completionFlags); + } + + void reset(WDFREQUEST newWdfRequest = WDF_NO_HANDLE) + { + if (m_wdfRequest != WDF_NO_HANDLE) + { + // We try to match the usage patterns that the driver would have typically used in the + // various scenarios. For instance, if the driver has set the information field, we'll + // call WdfRequestCompleteWithInformation instead of calling WdfRequestSetInformation + // followed by WdfRequestComplete. + +#if defined(WIL_KERNEL_MODE) + if (m_completionFlags.priorityBoostSet) + { + if (m_completionFlags.informationSet) + { + WdfRequestSetInformation(m_wdfRequest, m_information); + } + + WdfRequestCompleteWithPriorityBoost(m_wdfRequest, m_status, m_priorityBoost); + } + else +#endif + if (m_completionFlags.informationSet) + { + WdfRequestCompleteWithInformation(m_wdfRequest, m_status, m_information); + } + else + { + WdfRequestComplete(m_wdfRequest, m_status); + } + } + + // We call clear_state unconditionally just in case some parameters (status, + // information, etc.) were set prior to attaching a WDFREQUEST to this object. Those + // parameters are not considered relevant to the WDFREQUEST being attached to this + // object now. + clear_state(*this, newWdfRequest); + } + + private: + static void clear_state(wdf_request_completer &completer, WDFREQUEST newWdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT + { + completer.m_wdfRequest = newWdfRequest; + completer.m_status = STATUS_UNSUCCESSFUL; + completer.m_information = 0; +#if defined(WIL_KERNEL_MODE) + completer.m_priorityBoost = 0; +#endif + completer.m_completionFlags = {}; + } + + // Members are ordered in decreasing size to minimize padding. + + WDFREQUEST m_wdfRequest = WDF_NO_HANDLE; + + // This will not be used unless m_completionFlags.informationSet is set. + ULONG_PTR m_information = 0; + + // There is no reasonably default NTSTATUS value. Callers are expected to explicitly set a + // status value at the point where it is decided that the request needs to be completed. + NTSTATUS m_status = STATUS_UNSUCCESSFUL; // UMDF does not support WdfRequestCompleteWithPriorityBoost. #if defined(WIL_KERNEL_MODE) - // This will not be used unless m_completionFlags.priorityBoostSet is set. - CCHAR m_priorityBoost = 0; + // This will not be used unless m_completionFlags.priorityBoostSet is set. + CCHAR m_priorityBoost = 0; #endif - struct - { - UINT8 informationSet : 1; + struct + { + UINT8 informationSet : 1; #if defined(WIL_KERNEL_MODE) - UINT8 priorityBoostSet : 1; + UINT8 priorityBoostSet : 1; #endif - } m_completionFlags = {}; -}; + } m_completionFlags = {}; + }; #endif -#if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_CFGMGR32_H_) && (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_CFGMGR32_H_)) || \ +#if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_CFGMGR32_H_) && \ + (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_CFGMGR32_H_)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_CFGMGR32_H_ -/// @endcond -typedef unique_any unique_hcmnotification; + /// @endcond + typedef unique_any + unique_hcmnotification; #endif -#if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_SWDEVICE_H_) && (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_SWDEVICE_H_)) || \ +#if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && defined(_SWDEVICE_H_) && \ + (WINVER >= _WIN32_WINNT_WIN8) && !defined(__WIL_SWDEVICE_H_)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_SWDEVICE_H_ -/// @endcond -typedef unique_any unique_hswdevice; + /// @endcond + typedef unique_any unique_hswdevice; #endif #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM) #define __WIL_RESOURCE_WDM -/// @cond -namespace details -{ - struct kspin_lock_saved_irql + /// @cond + namespace details { - PKSPIN_LOCK spinLock = nullptr; - KIRQL savedIrql = PASSIVE_LEVEL; - - kspin_lock_saved_irql() = default; - - kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */) + struct kspin_lock_saved_irql { - // This constructor exists simply to allow conversion of the pointer type to - // pointer_storage type when constructing an invalid instance. The spinLock pointer - // is expected to be nullptr. - } + PKSPIN_LOCK spinLock = nullptr; + KIRQL savedIrql = PASSIVE_LEVEL; - // Exists to satisfy the interconvertibility requirement for pointer_storage and - // pointer. - WI_NODISCARD explicit operator PKSPIN_LOCK() const + kspin_lock_saved_irql() = default; + + kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */) + { + // This constructor exists simply to allow conversion of the pointer type to + // pointer_storage type when constructing an invalid instance. The spinLock pointer + // is expected to be nullptr. + } + + // Exists to satisfy the interconvertibility requirement for pointer_storage and + // pointer. + WI_NODISCARD explicit operator PKSPIN_LOCK() const + { + return spinLock; + } + + _IRQL_requires_(DISPATCH_LEVEL) static void Release( + _In_ _IRQL_restores_ const kspin_lock_saved_irql &spinLockSavedIrql) + { + KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql); + } + }; + + // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk + // function we can take the address of. + inline _IRQL_requires_min_(DISPATCH_LEVEL) void __stdcall ReleaseSpinLockFromDpcLevel( + _Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT { - return spinLock; + KeReleaseSpinLockFromDpcLevel(spinLock); } + } // namespace details + /// @endcond - _IRQL_requires_(DISPATCH_LEVEL) - static void Release(_In_ _IRQL_restores_ const kspin_lock_saved_irql& spinLockSavedIrql) - { - KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql); - } - }; + using kspin_lock_guard = unique_any; - // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk - // function we can take the address of. - inline _IRQL_requires_min_(DISPATCH_LEVEL) - void __stdcall ReleaseSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT - { - KeReleaseSpinLockFromDpcLevel(spinLock); - } -} // namespace details -/// @endcond - -using kspin_lock_guard = - unique_any; - -using kspin_lock_at_dpc_guard = - unique_any; - -WI_NODISCARD -inline _IRQL_requires_max_(DISPATCH_LEVEL) -_IRQL_saves_ -_IRQL_raises_(DISPATCH_LEVEL) -kspin_lock_guard acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock) -{ - details::kspin_lock_saved_irql spinLockSavedIrql; - KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql); - spinLockSavedIrql.spinLock = spinLock; - return kspin_lock_guard(spinLockSavedIrql); -} - -WI_NODISCARD -inline _IRQL_requires_min_(DISPATCH_LEVEL) -kspin_lock_at_dpc_guard acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock) -{ - KeAcquireSpinLockAtDpcLevel(spinLock); - return kspin_lock_at_dpc_guard(spinLock); -} - -class kernel_spin_lock -{ -public: - kernel_spin_lock() WI_NOEXCEPT - { - ::KeInitializeSpinLock(&m_kSpinLock); - } - - ~kernel_spin_lock() = default; - - // Cannot change memory location. - kernel_spin_lock(const kernel_spin_lock&) = delete; - kernel_spin_lock& operator=(const kernel_spin_lock&) = delete; - kernel_spin_lock(kernel_spin_lock&&) = delete; - kernel_spin_lock& operator=(kernel_spin_lock&&) = delete; + using kspin_lock_at_dpc_guard = unique_any; WI_NODISCARD - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_saves_ - _IRQL_raises_(DISPATCH_LEVEL) - kspin_lock_guard acquire() WI_NOEXCEPT + inline _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_ _IRQL_raises_(DISPATCH_LEVEL) kspin_lock_guard + acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock) { - return acquire_kspin_lock(&m_kSpinLock); + details::kspin_lock_saved_irql spinLockSavedIrql; + KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql); + spinLockSavedIrql.spinLock = spinLock; + return kspin_lock_guard(spinLockSavedIrql); } WI_NODISCARD - _IRQL_requires_min_(DISPATCH_LEVEL) - kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT + inline _IRQL_requires_min_(DISPATCH_LEVEL) kspin_lock_at_dpc_guard + acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock) { - return acquire_kspin_lock_at_dpc(&m_kSpinLock); + KeAcquireSpinLockAtDpcLevel(spinLock); + return kspin_lock_at_dpc_guard(spinLock); } -private: - KSPIN_LOCK m_kSpinLock; -}; - -/// @cond -namespace details -{ - template - class kernel_event_t + class kernel_spin_lock { - public: - explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT + public: + kernel_spin_lock() WI_NOEXCEPT { - ::KeInitializeEvent(&m_kernelEvent, static_cast(eventType), isSignaled ? TRUE : FALSE); + ::KeInitializeSpinLock(&m_kSpinLock); } + ~kernel_spin_lock() = default; + // Cannot change memory location. - kernel_event_t(const kernel_event_t&) = delete; - kernel_event_t(kernel_event_t&&) = delete; - kernel_event_t& operator=(const kernel_event_t&) = delete; - kernel_event_t& operator=(kernel_event_t&&) = delete; + kernel_spin_lock(const kernel_spin_lock &) = delete; + kernel_spin_lock &operator=(const kernel_spin_lock &) = delete; + kernel_spin_lock(kernel_spin_lock &&) = delete; + kernel_spin_lock &operator=(kernel_spin_lock &&) = delete; - // Get the underlying KEVENT structure for more advanced usages like - // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters. - PRKEVENT get() WI_NOEXCEPT + WI_NODISCARD + _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_ _IRQL_raises_(DISPATCH_LEVEL) kspin_lock_guard + acquire() WI_NOEXCEPT { - return &m_kernelEvent; + return acquire_kspin_lock(&m_kSpinLock); } - void clear() WI_NOEXCEPT + WI_NODISCARD + _IRQL_requires_min_(DISPATCH_LEVEL) kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT { - // The most common use-case is to clear the event with no interest in its previous - // value. Hence, that is the functionality we provide by default. If the previous - // value is required, one may .get() the underlying event object and call - // ::KeResetEvent(). - ::KeClearEvent(&m_kernelEvent); + return acquire_kspin_lock_at_dpc(&m_kSpinLock); } - // Returns the previous state of the event. - bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT - { - return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false; - } - - // Checks if the event is currently signaled. Does not change the state of the event. - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT - { - return ::KeReadStateEvent(const_cast(&m_kernelEvent)) ? true : false; - } - - // Return true if the wait was satisfied. Time is specified in 100ns units, relative - // (negative) or absolute (positive). For more details, see the documentation of - // KeWaitForSingleObject. - bool wait(LONGLONG waitTime) WI_NOEXCEPT - { - LARGE_INTEGER duration; - duration.QuadPart = waitTime; - return wait_for_single_object(&duration); - } - - // Waits indefinitely for the event to be signaled. - void wait() WI_NOEXCEPT - { - wait_for_single_object(nullptr); - } - - private: - bool wait_for_single_object(_In_opt_ LARGE_INTEGER* waitDuration) WI_NOEXCEPT - { - auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration); - - // We specified Executive and non-alertable, which means some of the return values are - // not possible. - WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT)); - return (status == STATUS_SUCCESS); - } - - KEVENT m_kernelEvent; + private: + KSPIN_LOCK m_kSpinLock; }; -} // namespace details -/// @endcond -using kernel_event_auto_reset = details::kernel_event_t; -using kernel_event_manual_reset = details::kernel_event_t; -using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types. - -/** -RAII class and lock-guards for a kernel FAST_MUTEX. -*/ - -using fast_mutex_guard = unique_any; - -WI_NODISCARD -inline _IRQL_requires_max_(APC_LEVEL) -fast_mutex_guard acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT -{ - ::ExAcquireFastMutex(fastMutex); - return fast_mutex_guard(fastMutex); -} - -WI_NODISCARD -inline _IRQL_requires_max_(APC_LEVEL) -fast_mutex_guard try_acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT -{ - if (::ExTryToAcquireFastMutex(fastMutex)) + /// @cond + namespace details { + template class kernel_event_t + { + public: + explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT + { + ::KeInitializeEvent(&m_kernelEvent, static_cast(eventType), isSignaled ? TRUE : FALSE); + } + + // Cannot change memory location. + kernel_event_t(const kernel_event_t &) = delete; + kernel_event_t(kernel_event_t &&) = delete; + kernel_event_t &operator=(const kernel_event_t &) = delete; + kernel_event_t &operator=(kernel_event_t &&) = delete; + + // Get the underlying KEVENT structure for more advanced usages like + // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters. + PRKEVENT get() WI_NOEXCEPT + { + return &m_kernelEvent; + } + + void clear() WI_NOEXCEPT + { + // The most common use-case is to clear the event with no interest in its previous + // value. Hence, that is the functionality we provide by default. If the previous + // value is required, one may .get() the underlying event object and call + // ::KeResetEvent(). + ::KeClearEvent(&m_kernelEvent); + } + + // Returns the previous state of the event. + bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT + { + return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false; + } + + // Checks if the event is currently signaled. Does not change the state of the event. + WI_NODISCARD bool is_signaled() const WI_NOEXCEPT + { + return ::KeReadStateEvent(const_cast(&m_kernelEvent)) ? true : false; + } + + // Return true if the wait was satisfied. Time is specified in 100ns units, relative + // (negative) or absolute (positive). For more details, see the documentation of + // KeWaitForSingleObject. + bool wait(LONGLONG waitTime) WI_NOEXCEPT + { + LARGE_INTEGER duration; + duration.QuadPart = waitTime; + return wait_for_single_object(&duration); + } + + // Waits indefinitely for the event to be signaled. + void wait() WI_NOEXCEPT + { + wait_for_single_object(nullptr); + } + + private: + bool wait_for_single_object(_In_opt_ LARGE_INTEGER *waitDuration) WI_NOEXCEPT + { + auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration); + + // We specified Executive and non-alertable, which means some of the return values are + // not possible. + WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT)); + return (status == STATUS_SUCCESS); + } + + KEVENT m_kernelEvent; + }; + } // namespace details + /// @endcond + + using kernel_event_auto_reset = details::kernel_event_t; + using kernel_event_manual_reset = details::kernel_event_t; + using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types. + + /** + RAII class and lock-guards for a kernel FAST_MUTEX. + */ + + using fast_mutex_guard = + unique_any; + + WI_NODISCARD + inline _IRQL_requires_max_(APC_LEVEL) fast_mutex_guard acquire_fast_mutex(FAST_MUTEX *fastMutex) WI_NOEXCEPT + { + ::ExAcquireFastMutex(fastMutex); return fast_mutex_guard(fastMutex); } - else - { - return fast_mutex_guard(); - } -} - -class fast_mutex -{ -public: - fast_mutex() WI_NOEXCEPT - { - ::ExInitializeFastMutex(&m_fastMutex); - } - - ~fast_mutex() WI_NOEXCEPT = default; - - // Cannot change memory location. - fast_mutex(const fast_mutex&) = delete; - fast_mutex& operator=(const fast_mutex&) = delete; - fast_mutex(fast_mutex&&) = delete; - fast_mutex& operator=(fast_mutex&&) = delete; - - // Calls ExAcquireFastMutex. Returned wil::unique_any object calls ExReleaseFastMutex on - // destruction. - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard acquire() WI_NOEXCEPT - { - return acquire_fast_mutex(&m_fastMutex); - } - - // Calls ExTryToAcquireFastMutex. Returned wil::unique_any may be empty. If non-empty, it - // calls ExReleaseFastMutex on destruction. - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard try_acquire() WI_NOEXCEPT - { - return try_acquire_fast_mutex(&m_fastMutex); - } - -private: - FAST_MUTEX m_fastMutex; -}; - -/// @cond -namespace details -{ - _IRQL_requires_max_(APC_LEVEL) - inline void release_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT - { - ::ExReleaseFastMutexUnsafe(fastMutex); - ::KeLeaveCriticalRegion(); - } -} // namespace details -/// @endcond - -using fast_mutex_with_critical_region_guard = - unique_any; - -WI_NODISCARD -inline _IRQL_requires_max_(APC_LEVEL) -fast_mutex_with_critical_region_guard acquire_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT -{ - ::KeEnterCriticalRegion(); - ::ExAcquireFastMutexUnsafe(fastMutex); - return fast_mutex_with_critical_region_guard(fastMutex); -} - -// A FAST_MUTEX lock class that calls KeEnterCriticalRegion and then ExAcquireFastMutexUnsafe. -// Returned wil::unique_any lock-guard calls ExReleaseFastMutexUnsafe and KeLeaveCriticalRegion -// on destruction. This is useful if calling code wants to stay at PASSIVE_LEVEL. -class fast_mutex_with_critical_region -{ -public: - fast_mutex_with_critical_region() WI_NOEXCEPT - { - ::ExInitializeFastMutex(&m_fastMutex); - } - - ~fast_mutex_with_critical_region() WI_NOEXCEPT = default; - - // Cannot change memory location. - fast_mutex_with_critical_region(const fast_mutex_with_critical_region&) = delete; - fast_mutex_with_critical_region& operator=(const fast_mutex_with_critical_region&) = delete; - fast_mutex_with_critical_region(fast_mutex_with_critical_region&&) = delete; - fast_mutex_with_critical_region& operator=(fast_mutex_with_critical_region&&) = delete; WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_with_critical_region_guard acquire() WI_NOEXCEPT + inline _IRQL_requires_max_(APC_LEVEL) fast_mutex_guard try_acquire_fast_mutex(FAST_MUTEX *fastMutex) WI_NOEXCEPT { - return acquire_fast_mutex_with_critical_region(&m_fastMutex); + if (::ExTryToAcquireFastMutex(fastMutex)) + { + return fast_mutex_guard(fastMutex); + } + else + { + return fast_mutex_guard(); + } } -private: - FAST_MUTEX m_fastMutex; -}; + class fast_mutex + { + public: + fast_mutex() WI_NOEXCEPT + { + ::ExInitializeFastMutex(&m_fastMutex); + } -//! A type that calls KeLeaveCriticalRegion on destruction (or reset()). -using unique_leave_critical_region_call = unique_call; + ~fast_mutex() WI_NOEXCEPT = default; -//! Disables user APCs and normal kernel APCs; returns an RAII object that reverts -WI_NODISCARD inline unique_leave_critical_region_call enter_critical_region() -{ - KeEnterCriticalRegion(); - return {}; -} + // Cannot change memory location. + fast_mutex(const fast_mutex &) = delete; + fast_mutex &operator=(const fast_mutex &) = delete; + fast_mutex(fast_mutex &&) = delete; + fast_mutex &operator=(fast_mutex &&) = delete; -//! A type that calls KeLeaveGuardedRegion on destruction (or reset()). -using unique_leave_guarded_region_call = unique_call; + // Calls ExAcquireFastMutex. Returned wil::unique_any object calls ExReleaseFastMutex on + // destruction. + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) fast_mutex_guard acquire() WI_NOEXCEPT + { + return acquire_fast_mutex(&m_fastMutex); + } -//! Disables all APCs; returns an RAII object that reverts -WI_NODISCARD inline unique_leave_guarded_region_call enter_guarded_region() -{ - KeEnterGuardedRegion(); - return {}; -} + // Calls ExTryToAcquireFastMutex. Returned wil::unique_any may be empty. If non-empty, it + // calls ExReleaseFastMutex on destruction. + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) fast_mutex_guard try_acquire() WI_NOEXCEPT + { + return try_acquire_fast_mutex(&m_fastMutex); + } + + private: + FAST_MUTEX m_fastMutex; + }; + + /// @cond + namespace details + { + _IRQL_requires_max_(APC_LEVEL) inline void release_fast_mutex_with_critical_region(FAST_MUTEX *fastMutex) + WI_NOEXCEPT + { + ::ExReleaseFastMutexUnsafe(fastMutex); + ::KeLeaveCriticalRegion(); + } + } // namespace details + /// @endcond + + using fast_mutex_with_critical_region_guard = + unique_any; + + WI_NODISCARD + inline _IRQL_requires_max_(APC_LEVEL) fast_mutex_with_critical_region_guard + acquire_fast_mutex_with_critical_region(FAST_MUTEX *fastMutex) WI_NOEXCEPT + { + ::KeEnterCriticalRegion(); + ::ExAcquireFastMutexUnsafe(fastMutex); + return fast_mutex_with_critical_region_guard(fastMutex); + } + + // A FAST_MUTEX lock class that calls KeEnterCriticalRegion and then ExAcquireFastMutexUnsafe. + // Returned wil::unique_any lock-guard calls ExReleaseFastMutexUnsafe and KeLeaveCriticalRegion + // on destruction. This is useful if calling code wants to stay at PASSIVE_LEVEL. + class fast_mutex_with_critical_region + { + public: + fast_mutex_with_critical_region() WI_NOEXCEPT + { + ::ExInitializeFastMutex(&m_fastMutex); + } + + ~fast_mutex_with_critical_region() WI_NOEXCEPT = default; + + // Cannot change memory location. + fast_mutex_with_critical_region(const fast_mutex_with_critical_region &) = delete; + fast_mutex_with_critical_region &operator=(const fast_mutex_with_critical_region &) = delete; + fast_mutex_with_critical_region(fast_mutex_with_critical_region &&) = delete; + fast_mutex_with_critical_region &operator=(fast_mutex_with_critical_region &&) = delete; + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) fast_mutex_with_critical_region_guard acquire() WI_NOEXCEPT + { + return acquire_fast_mutex_with_critical_region(&m_fastMutex); + } + + private: + FAST_MUTEX m_fastMutex; + }; + + //! A type that calls KeLeaveCriticalRegion on destruction (or reset()). + using unique_leave_critical_region_call = unique_call; + + //! Disables user APCs and normal kernel APCs; returns an RAII object that reverts + WI_NODISCARD inline unique_leave_critical_region_call enter_critical_region() + { + KeEnterCriticalRegion(); + return {}; + } + + //! A type that calls KeLeaveGuardedRegion on destruction (or reset()). + using unique_leave_guarded_region_call = unique_call; + + //! Disables all APCs; returns an RAII object that reverts + WI_NODISCARD inline unique_leave_guarded_region_call enter_guarded_region() + { + KeEnterGuardedRegion(); + return {}; + } //! WDM version of EX_PUSH_LOCK is available starting with Windows 10 1809 #if (NTDDI_VERSION >= NTDDI_WIN10_RS5) -/// @cond -namespace details -{ - _IRQL_requires_max_(APC_LEVEL) - inline void release_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT + /// @cond + namespace details { - ::ExReleasePushLockExclusive(pushLock); - ::KeLeaveCriticalRegion(); - } + _IRQL_requires_max_(APC_LEVEL) inline void release_push_lock_exclusive(EX_PUSH_LOCK *pushLock) WI_NOEXCEPT + { + ::ExReleasePushLockExclusive(pushLock); + ::KeLeaveCriticalRegion(); + } - _IRQL_requires_max_(APC_LEVEL) - inline void release_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT - { - ::ExReleasePushLockShared(pushLock); - ::KeLeaveCriticalRegion(); - } -} // namespace details -/// @endcond + _IRQL_requires_max_(APC_LEVEL) inline void release_push_lock_shared(EX_PUSH_LOCK *pushLock) WI_NOEXCEPT + { + ::ExReleasePushLockShared(pushLock); + ::KeLeaveCriticalRegion(); + } + } // namespace details + /// @endcond -using push_lock_exclusive_guard = - unique_any; + using push_lock_exclusive_guard = + unique_any; -using push_lock_shared_guard = - unique_any; - -WI_NODISCARD -inline _IRQL_requires_max_(APC_LEVEL) -push_lock_exclusive_guard acquire_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT -{ - ::KeEnterCriticalRegion(); - ::ExAcquirePushLockExclusive(pushLock); - return push_lock_exclusive_guard(pushLock); -} - -WI_NODISCARD -inline _IRQL_requires_max_(APC_LEVEL) -push_lock_shared_guard acquire_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT -{ - ::KeEnterCriticalRegion(); - ::ExAcquirePushLockShared(pushLock); - return push_lock_shared_guard(pushLock); -} - -class push_lock -{ -public: - push_lock() WI_NOEXCEPT - { - ::ExInitializePushLock(&m_pushLock); - } - - ~push_lock() WI_NOEXCEPT = default; - - // Cannot change memory location. - push_lock(const push_lock&) = delete; - push_lock& operator=(const push_lock&) = delete; - push_lock(push_lock&&) = delete; - push_lock& operator=(push_lock&&) = delete; + using push_lock_shared_guard = unique_any; WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - push_lock_exclusive_guard acquire_exclusive() WI_NOEXCEPT + inline _IRQL_requires_max_(APC_LEVEL) push_lock_exclusive_guard + acquire_push_lock_exclusive(EX_PUSH_LOCK *pushLock) WI_NOEXCEPT { - return acquire_push_lock_exclusive(&m_pushLock); + ::KeEnterCriticalRegion(); + ::ExAcquirePushLockExclusive(pushLock); + return push_lock_exclusive_guard(pushLock); } WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - push_lock_shared_guard acquire_shared() WI_NOEXCEPT + inline _IRQL_requires_max_(APC_LEVEL) push_lock_shared_guard + acquire_push_lock_shared(EX_PUSH_LOCK *pushLock) WI_NOEXCEPT { - return acquire_push_lock_shared(&m_pushLock); + ::KeEnterCriticalRegion(); + ::ExAcquirePushLockShared(pushLock); + return push_lock_shared_guard(pushLock); } -private: - EX_PUSH_LOCK m_pushLock; -}; + class push_lock + { + public: + push_lock() WI_NOEXCEPT + { + ::ExInitializePushLock(&m_pushLock); + } + + ~push_lock() WI_NOEXCEPT = default; + + // Cannot change memory location. + push_lock(const push_lock &) = delete; + push_lock &operator=(const push_lock &) = delete; + push_lock(push_lock &&) = delete; + push_lock &operator=(push_lock &&) = delete; + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) push_lock_exclusive_guard acquire_exclusive() WI_NOEXCEPT + { + return acquire_push_lock_exclusive(&m_pushLock); + } + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) push_lock_shared_guard acquire_shared() WI_NOEXCEPT + { + return acquire_push_lock_shared(&m_pushLock); + } + + private: + EX_PUSH_LOCK m_pushLock; + }; #endif -/// @cond -namespace details -{ - // Define a templated type for pool functions in order to satisfy overload resolution below - template - struct pool_helpers + /// @cond + namespace details { - static inline _IRQL_requires_max_(DISPATCH_LEVEL) - void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT + // Define a templated type for pool functions in order to satisfy overload resolution below + template struct pool_helpers { - if (value) + static inline _IRQL_requires_max_(DISPATCH_LEVEL) void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT { - ExFreePoolWithTag(value, tag); + if (value) + { + ExFreePoolWithTag(value, tag); + } } - } - }; -} // namespace details -/// @endcond + }; + } // namespace details + /// @endcond -template -using unique_tagged_pool_ptr = - unique_any::FreePoolWithTag), &details::pool_helpers::FreePoolWithTag>; + template + using unique_tagged_pool_ptr = unique_any::FreePoolWithTag), + &details::pool_helpers::FreePoolWithTag>; -// For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp. -using unique_allocated_irp = wil::unique_any; -using unique_io_workitem = - wil::unique_any; + // For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp. + using unique_allocated_irp = + wil::unique_any; + using unique_io_workitem = + wil::unique_any; #endif // __WIL_RESOURCE_WDM #if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_ZWAPI_)) && !defined(__WIL_RESOURCE_ZWAPI) #define __WIL_RESOURCE_ZWAPI -using unique_kernel_handle = wil::unique_any; + using unique_kernel_handle = wil::unique_any; #endif // __WIL_RESOURCE_ZWAPI -#if (defined(WINTRUST_H) && defined(SOFTPUB_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_WINTRUST)) || \ +#if (defined(WINTRUST_H) && defined(SOFTPUB_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && \ + !defined(__WIL_WINTRUST)) || \ defined(WIL_DOXYGEN) /// @cond #define __WIL_WINTRUST -namespace details -{ - inline void __stdcall CloseWintrustData(_Inout_ WINTRUST_DATA* wtData) WI_NOEXCEPT + namespace details { - GUID guidV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; - wtData->dwStateAction = WTD_STATEACTION_CLOSE; - WinVerifyTrust(static_cast(INVALID_HANDLE_VALUE), &guidV2, wtData); - } -} // namespace details -/// @endcond -typedef wil::unique_struct unique_wintrust_data; + inline void __stdcall CloseWintrustData(_Inout_ WINTRUST_DATA *wtData) WI_NOEXCEPT + { + GUID guidV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; + wtData->dwStateAction = WTD_STATEACTION_CLOSE; + WinVerifyTrust(static_cast(INVALID_HANDLE_VALUE), &guidV2, wtData); + } + } // namespace details + /// @endcond + typedef wil::unique_struct + unique_wintrust_data; #endif // __WIL_WINTRUST -#if (defined(MSCAT_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_MSCAT)) || defined(WIL_DOXYGEN) +#if (defined(MSCAT_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_MSCAT)) || \ + defined(WIL_DOXYGEN) /// @cond #define __WIL_MSCAT -namespace details -{ - inline void __stdcall CryptCATAdminReleaseContextNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ HCATADMIN handle) WI_NOEXCEPT + namespace details { - CryptCATAdminReleaseContext(handle, 0); - } -} // namespace details -/// @endcond -typedef wil::unique_any unique_hcatadmin; + inline void __stdcall CryptCATAdminReleaseContextNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ HCATADMIN handle) + WI_NOEXCEPT + { + CryptCATAdminReleaseContext(handle, 0); + } + } // namespace details + /// @endcond + typedef wil::unique_any + unique_hcatadmin; #if defined(WIL_RESOURCE_STL) -typedef shared_any shared_hcatadmin; -struct hcatinfo_deleter -{ - hcatinfo_deleter(wil::shared_hcatadmin handle) WI_NOEXCEPT : m_hCatAdmin(wistd::move(handle)) + typedef shared_any shared_hcatadmin; + struct hcatinfo_deleter { - } - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ HCATINFO handle) const WI_NOEXCEPT - { - CryptCATAdminReleaseCatalogContext(m_hCatAdmin.get(), handle, 0); - } - wil::shared_hcatadmin m_hCatAdmin; -}; -// This stores HCATINFO, i.e. HANDLE (void *) -typedef wistd::unique_ptr unique_hcatinfo; - -/// @cond -namespace details -{ - class crypt_catalog_enumerator - { - wil::unique_hcatinfo m_hCatInfo; - const BYTE* m_hash; - DWORD m_hashLen; - bool m_initialized = false; - - struct ref + hcatinfo_deleter(wil::shared_hcatadmin handle) WI_NOEXCEPT : m_hCatAdmin(wistd::move(handle)) { - explicit ref(crypt_catalog_enumerator& r) WI_NOEXCEPT : m_r(r) - { - } - - WI_NODISCARD operator HCATINFO() const WI_NOEXCEPT - { - return m_r.current(); - } - - wil::unique_hcatinfo move_from_unique_hcatinfo() WI_NOEXCEPT - { - wil::unique_hcatinfo info(wistd::move(m_r.m_hCatInfo)); - return info; - } - - WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT - { - return m_r.m_hCatInfo == nullptr; - } - - WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT - { - return !(*this == nullptr); - } - - private: - crypt_catalog_enumerator& m_r; - }; - - struct iterator + } + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ HCATINFO handle) const WI_NOEXCEPT { + CryptCATAdminReleaseCatalogContext(m_hCatAdmin.get(), handle, 0); + } + wil::shared_hcatadmin m_hCatAdmin; + }; + // This stores HCATINFO, i.e. HANDLE (void *) + typedef wistd::unique_ptr unique_hcatinfo; + + /// @cond + namespace details + { + class crypt_catalog_enumerator + { + wil::unique_hcatinfo m_hCatInfo; + const BYTE *m_hash; + DWORD m_hashLen; + bool m_initialized = false; + + struct ref + { + explicit ref(crypt_catalog_enumerator &r) WI_NOEXCEPT : m_r(r) + { + } + + WI_NODISCARD operator HCATINFO() const WI_NOEXCEPT + { + return m_r.current(); + } + + wil::unique_hcatinfo move_from_unique_hcatinfo() WI_NOEXCEPT + { + wil::unique_hcatinfo info(wistd::move(m_r.m_hCatInfo)); + return info; + } + + WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT + { + return m_r.m_hCatInfo == nullptr; + } + + WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT + { + return !(*this == nullptr); + } + + private: + crypt_catalog_enumerator &m_r; + }; + + struct iterator + { #if WIL_USE_STL || defined(WIL_DOXYGEN) - // muse be input_iterator_tag as use of one instance invalidates the other. - typedef ::std::input_iterator_tag iterator_category; + // muse be input_iterator_tag as use of one instance invalidates the other. + typedef ::std::input_iterator_tag iterator_category; #endif - explicit iterator(crypt_catalog_enumerator* r) WI_NOEXCEPT : m_r(r) - { - } - - iterator(const iterator&) = default; - iterator(iterator&&) = default; - iterator& operator=(const iterator&) = default; - iterator& operator=(iterator&&) = default; - - WI_NODISCARD bool operator==(const iterator& rhs) const WI_NOEXCEPT - { - if (rhs.m_r == m_r) + explicit iterator(crypt_catalog_enumerator *r) WI_NOEXCEPT : m_r(r) { - return true; } - return (*this == nullptr) && (rhs == nullptr); - } + iterator(const iterator &) = default; + iterator(iterator &&) = default; + iterator &operator=(const iterator &) = default; + iterator &operator=(iterator &&) = default; - WI_NODISCARD bool operator!=(const iterator& rhs) const WI_NOEXCEPT - { - return !(rhs == *this); - } - - WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT - { - return nullptr == m_r || nullptr == m_r->current(); - } - - WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT - { - return !(*this == nullptr); - } - - iterator& operator++() WI_NOEXCEPT - { - if (m_r != nullptr) + WI_NODISCARD bool operator==(const iterator &rhs) const WI_NOEXCEPT { - m_r->next(); + if (rhs.m_r == m_r) + { + return true; + } + + return (*this == nullptr) && (rhs == nullptr); } - return *this; - } + WI_NODISCARD bool operator!=(const iterator &rhs) const WI_NOEXCEPT + { + return !(rhs == *this); + } - WI_NODISCARD ref operator*() const WI_NOEXCEPT + WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT + { + return nullptr == m_r || nullptr == m_r->current(); + } + + WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT + { + return !(*this == nullptr); + } + + iterator &operator++() WI_NOEXCEPT + { + if (m_r != nullptr) + { + m_r->next(); + } + + return *this; + } + + WI_NODISCARD ref operator*() const WI_NOEXCEPT + { + return ref(*m_r); + } + + private: + crypt_catalog_enumerator *m_r; + }; + + shared_hcatadmin &hcatadmin() WI_NOEXCEPT { - return ref(*m_r); + return m_hCatInfo.get_deleter().m_hCatAdmin; } - private: - crypt_catalog_enumerator* m_r; + bool move_next() WI_NOEXCEPT + { + HCATINFO prevCatInfo = m_hCatInfo.release(); + m_hCatInfo.reset(::CryptCATAdminEnumCatalogFromHash(hcatadmin().get(), const_cast(m_hash), + m_hashLen, 0, &prevCatInfo)); + return !!m_hCatInfo; + } + + HCATINFO next() WI_NOEXCEPT + { + if (m_initialized && m_hCatInfo) + { + move_next(); + } + + return current(); + } + + HCATINFO init() WI_NOEXCEPT + { + if (!m_initialized) + { + m_initialized = true; + move_next(); + } + + return current(); + } + + HCATINFO current() WI_NOEXCEPT + { + return m_hCatInfo.get(); + } + + public: + crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, const BYTE *hash, DWORD hashLen) WI_NOEXCEPT + : m_hCatInfo(nullptr, hCatAdmin), + m_hash(hash), + m_hashLen(hashLen) + // , m_initialized(false) // redundant + { + } + + WI_NODISCARD iterator begin() WI_NOEXCEPT + { + init(); + return iterator(this); + } + + WI_NODISCARD iterator end() const WI_NOEXCEPT + { + return iterator(nullptr); + } + + crypt_catalog_enumerator(crypt_catalog_enumerator &&) = default; + crypt_catalog_enumerator &operator=(crypt_catalog_enumerator &&) = default; + + crypt_catalog_enumerator(const crypt_catalog_enumerator &) = delete; + crypt_catalog_enumerator &operator=(const crypt_catalog_enumerator &) = delete; }; + } // namespace details + /// @endcond - shared_hcatadmin& hcatadmin() WI_NOEXCEPT - { - return m_hCatInfo.get_deleter().m_hCatAdmin; - } + /** Use to enumerate catalogs containing a hash with a range-based for. + This avoids handling a raw resource to call CryptCATAdminEnumCatalogFromHash correctly. + Example: + `for (auto&& cat : wil::make_catalog_enumerator(hCatAdmin, hash, hashLen)) + { CryptCATCatalogInfoFromContext(cat, &catInfo, 0); }` */ + inline details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, + _In_count_(hashLen) const BYTE *hash, + DWORD hashLen) WI_NOEXCEPT + { + return details::crypt_catalog_enumerator(hCatAdmin, hash, hashLen); + } - bool move_next() WI_NOEXCEPT - { - HCATINFO prevCatInfo = m_hCatInfo.release(); - m_hCatInfo.reset(::CryptCATAdminEnumCatalogFromHash(hcatadmin().get(), const_cast(m_hash), m_hashLen, 0, &prevCatInfo)); - return !!m_hCatInfo; - } - - HCATINFO next() WI_NOEXCEPT - { - if (m_initialized && m_hCatInfo) - { - move_next(); - } - - return current(); - } - - HCATINFO init() WI_NOEXCEPT - { - if (!m_initialized) - { - m_initialized = true; - move_next(); - } - - return current(); - } - - HCATINFO current() WI_NOEXCEPT - { - return m_hCatInfo.get(); - } - - public: - crypt_catalog_enumerator(wil::shared_hcatadmin& hCatAdmin, const BYTE* hash, DWORD hashLen) WI_NOEXCEPT - : m_hCatInfo(nullptr, hCatAdmin), - m_hash(hash), - m_hashLen(hashLen) - // , m_initialized(false) // redundant - { - } - - WI_NODISCARD iterator begin() WI_NOEXCEPT - { - init(); - return iterator(this); - } - - WI_NODISCARD iterator end() const WI_NOEXCEPT - { - return iterator(nullptr); - } - - crypt_catalog_enumerator(crypt_catalog_enumerator&&) = default; - crypt_catalog_enumerator& operator=(crypt_catalog_enumerator&&) = default; - - crypt_catalog_enumerator(const crypt_catalog_enumerator&) = delete; - crypt_catalog_enumerator& operator=(const crypt_catalog_enumerator&) = delete; - }; -} // namespace details -/// @endcond - -/** Use to enumerate catalogs containing a hash with a range-based for. -This avoids handling a raw resource to call CryptCATAdminEnumCatalogFromHash correctly. -Example: -`for (auto&& cat : wil::make_catalog_enumerator(hCatAdmin, hash, hashLen)) - { CryptCATCatalogInfoFromContext(cat, &catInfo, 0); }` */ -inline details::crypt_catalog_enumerator make_crypt_catalog_enumerator( - wil::shared_hcatadmin& hCatAdmin, _In_count_(hashLen) const BYTE* hash, DWORD hashLen) WI_NOEXCEPT -{ - return details::crypt_catalog_enumerator(hCatAdmin, hash, hashLen); -} - -template -details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcatadmin& hCatAdmin, const BYTE (&hash)[Size]) WI_NOEXCEPT -{ - static_assert(Size <= static_cast(0xffffffffUL), "Array size truncated"); - return details::crypt_catalog_enumerator(hCatAdmin, hash, static_cast(Size)); -} + template + details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, + const BYTE (&hash)[Size]) WI_NOEXCEPT + { + static_assert(Size <= static_cast(0xffffffffUL), "Array size truncated"); + return details::crypt_catalog_enumerator(hCatAdmin, hash, static_cast(Size)); + } #endif // WI_RESOURCE_STL @@ -7501,206 +7648,202 @@ details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcat #if !defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) /// @cond #define __WIL_RESOURCE_LOCK_ENFORCEMENT -/// @endcond + /// @endcond -/// @cond -namespace details -{ - // Only those lock types specialized by lock_proof_traits will allow either a write_lock_required or - // read_lock_required to be constructed. The allows_exclusive value indicates if the type represents an exclusive, - // write-safe lock acquisition, or a shared, read-only lock acquisition. - template - struct lock_proof_traits + /// @cond + namespace details { - }; + // Only those lock types specialized by lock_proof_traits will allow either a write_lock_required or + // read_lock_required to be constructed. The allows_exclusive value indicates if the type represents an + // exclusive, write-safe lock acquisition, or a shared, read-only lock acquisition. + template struct lock_proof_traits + { + }; - // Base for specializing lock_proof_traits where the lock type is shared - struct shared_lock_proof - { - static constexpr bool allows_shared = true; - }; + // Base for specializing lock_proof_traits where the lock type is shared + struct shared_lock_proof + { + static constexpr bool allows_shared = true; + }; - // Base for specializing lock_proof_traits where the lock type is exclusive (super-set of shared_lock_proof) - struct exclusive_lock_proof : shared_lock_proof - { - static constexpr bool allows_exclusive = true; - }; -} // namespace details -/// @endcond - -/** -Functions that need an exclusive lock use can use write_lock_required as a parameter to enforce lock -safety at compile time. Similarly, read_lock_required may stand as a parameter where shared ownership -of a lock is required. These are empty structs that will never be used, other than passing them on to -another function that requires them. - -These types are implicitly convertible from various lock holding types, enabling callers to provide them as -proof of the lock that they hold. - -The following example is intentionally contrived to demonstrate multiple use cases: - - Methods that require only shared/read access - - Methods that require only exclusive write access - - Methods that pass their proof-of-lock to a helper -~~~ - class RemoteControl - { - public: - void VolumeUp(); - int GetVolume(); - private: - int GetCurrentVolume(wil::read_lock_required); - void AdjustVolume(int delta, wil::write_lock_required); - void SetNewVolume(int newVolume, wil::write_lock_required); - - int m_currentVolume = 0; - wil::srwlock m_lock; - }; - - void RemoteControl::VolumeUp() - { - auto writeLock = m_lock.lock_exclusive(); - AdjustVolume(1, writeLock); - } - - int RemoteControl::GetVolume() - { - auto readLock = m_lock.lock_shared(); - return GetCurrentVolume(readLock); - } - - int RemoteControl::GetCurrentVolume(wil::read_lock_required) - { - return m_currentVolume; - } - - void AdjustVolume(int delta, wil::write_lock_required lockProof) - { - const auto currentVolume = GetCurrentVolume(lockProof); - SetNewVolume(currentVolume + delta, lockProof); - } - - void RemoteControl::SetNewVolume(int newVolume, wil::write_lock_required) - { - m_currentVolume = newVolume; - } -~~~ - -In this design it is impossible to not meet the "lock must be held" precondition and the function parameter types -help you understand which one. - -Cases not handled: - - Functions that need the lock held, but fail to specify this fact by requiring a lock required parameter need - to be found via code inspection. - - Recursively taking a lock, when it is already held, is not avoided in this pattern - - Readers will learn to be suspicious of acquiring a lock in functions with lock required parameters. - - Designs with multiple locks, that must be careful to take them in the same order every time, are not helped - by this pattern. - - Locking the wrong object - - Use of a std::lock type that has not actually be secured yet (such as by std::try_to_lock or std::defer_lock) - - or use of a lock type that had been acquired but has since been released, reset, or otherwise unlocked - -These utility types are not fool-proof against all lock misuse, anti-patterns, or other complex yet valid -scenarios. However on the net, their usage in typical cases can assist in creating clearer, self-documenting -code that catches the common issues of forgetting to hold a lock or forgetting whether a lock is required to -call another method safely. -*/ -struct write_lock_required -{ - /** - Construct a new write_lock_required object for use as proof that an exclusive lock has been acquired. - */ - template - write_lock_required(const TLockProof&, wistd::enable_if_t::allows_exclusive, int> = 0) - { - } - - write_lock_required() = delete; // No default construction -}; - -/** -Stands as proof that a shared lock has been acquired. See write_lock_required for more information. -*/ -struct read_lock_required -{ - /** - Construct a new read_lock_required object for use as proof that a shared lock has been acquired. - */ - template - read_lock_required(const TLockProof&, wistd::enable_if_t::allows_shared, int> = 0) - { - } + // Base for specializing lock_proof_traits where the lock type is exclusive (super-set of shared_lock_proof) + struct exclusive_lock_proof : shared_lock_proof + { + static constexpr bool allows_exclusive = true; + }; + } // namespace details + /// @endcond /** - Uses a prior write_lock_required object to construct a read_lock_required object as proof that at shared lock - has been acquired. (Exclusive locks held are presumed to suffice for proof of a read lock) - */ - read_lock_required(const write_lock_required&) - { - } + Functions that need an exclusive lock use can use write_lock_required as a parameter to enforce lock + safety at compile time. Similarly, read_lock_required may stand as a parameter where shared ownership + of a lock is required. These are empty structs that will never be used, other than passing them on to + another function that requires them. - read_lock_required() = delete; // No default construction -}; + These types are implicitly convertible from various lock holding types, enabling callers to provide them as + proof of the lock that they hold. + + The following example is intentionally contrived to demonstrate multiple use cases: + - Methods that require only shared/read access + - Methods that require only exclusive write access + - Methods that pass their proof-of-lock to a helper + ~~~ + class RemoteControl + { + public: + void VolumeUp(); + int GetVolume(); + private: + int GetCurrentVolume(wil::read_lock_required); + void AdjustVolume(int delta, wil::write_lock_required); + void SetNewVolume(int newVolume, wil::write_lock_required); + + int m_currentVolume = 0; + wil::srwlock m_lock; + }; + + void RemoteControl::VolumeUp() + { + auto writeLock = m_lock.lock_exclusive(); + AdjustVolume(1, writeLock); + } + + int RemoteControl::GetVolume() + { + auto readLock = m_lock.lock_shared(); + return GetCurrentVolume(readLock); + } + + int RemoteControl::GetCurrentVolume(wil::read_lock_required) + { + return m_currentVolume; + } + + void AdjustVolume(int delta, wil::write_lock_required lockProof) + { + const auto currentVolume = GetCurrentVolume(lockProof); + SetNewVolume(currentVolume + delta, lockProof); + } + + void RemoteControl::SetNewVolume(int newVolume, wil::write_lock_required) + { + m_currentVolume = newVolume; + } + ~~~ + + In this design it is impossible to not meet the "lock must be held" precondition and the function parameter types + help you understand which one. + + Cases not handled: + - Functions that need the lock held, but fail to specify this fact by requiring a lock required parameter need + to be found via code inspection. + - Recursively taking a lock, when it is already held, is not avoided in this pattern + - Readers will learn to be suspicious of acquiring a lock in functions with lock required parameters. + - Designs with multiple locks, that must be careful to take them in the same order every time, are not helped + by this pattern. + - Locking the wrong object + - Use of a std::lock type that has not actually be secured yet (such as by std::try_to_lock or std::defer_lock) + - or use of a lock type that had been acquired but has since been released, reset, or otherwise unlocked + + These utility types are not fool-proof against all lock misuse, anti-patterns, or other complex yet valid + scenarios. However on the net, their usage in typical cases can assist in creating clearer, self-documenting + code that catches the common issues of forgetting to hold a lock or forgetting whether a lock is required to + call another method safely. + */ + struct write_lock_required + { + /** + Construct a new write_lock_required object for use as proof that an exclusive lock has been acquired. + */ + template + write_lock_required(const TLockProof &, + wistd::enable_if_t::allows_exclusive, int> = 0) + { + } + + write_lock_required() = delete; // No default construction + }; + + /** + Stands as proof that a shared lock has been acquired. See write_lock_required for more information. + */ + struct read_lock_required + { + /** + Construct a new read_lock_required object for use as proof that a shared lock has been acquired. + */ + template + read_lock_required(const TLockProof &, + wistd::enable_if_t::allows_shared, int> = 0) + { + } + + /** + Uses a prior write_lock_required object to construct a read_lock_required object as proof that at shared lock + has been acquired. (Exclusive locks held are presumed to suffice for proof of a read lock) + */ + read_lock_required(const write_lock_required &) + { + } + + read_lock_required() = delete; // No default construction + }; #endif // __WIL_RESOURCE_LOCK_ENFORCEMENT #if defined(__WIL_WINBASE_) && !defined(__WIL__RESOURCE_LOCKPROOF_WINBASE) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) #define __WIL__RESOURCE_LOCKPROOF_WINBASE -/// @cond -namespace details -{ - // Specializations for srwlock - template <> - struct lock_proof_traits : shared_lock_proof + /// @cond + namespace details { - }; + // Specializations for srwlock + template <> struct lock_proof_traits : shared_lock_proof + { + }; - template <> - struct lock_proof_traits : exclusive_lock_proof - { - }; + template <> struct lock_proof_traits : exclusive_lock_proof + { + }; - // Specialization for critical_section - template <> - struct lock_proof_traits : exclusive_lock_proof - { - }; -} // namespace details -/// @endcond + // Specialization for critical_section + template <> struct lock_proof_traits : exclusive_lock_proof + { + }; + } // namespace details + /// @endcond #endif //__WIL__RESOURCE_LOCKPROOF_WINBASE #if defined(_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_MUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) #define __WIL__RESOURCE_LOCKPROOF_MUTEX -/// @cond -namespace details -{ - template - struct lock_proof_traits> : exclusive_lock_proof + /// @cond + namespace details { - }; + template struct lock_proof_traits> : exclusive_lock_proof + { + }; - template - struct lock_proof_traits> : exclusive_lock_proof - { - }; -} // namespace details -/// @endcond + template struct lock_proof_traits> : exclusive_lock_proof + { + }; + } // namespace details + /// @endcond #endif //__WIL__RESOURCE_LOCKPROOF_MUTEX -#if defined(_SHARED_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) +#if defined(_SHARED_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX) && \ + defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) #define __WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX -/// @cond -namespace details -{ - template - struct lock_proof_traits> : shared_lock_proof + /// @cond + namespace details { - }; -} // namespace details -/// @endcond + template struct lock_proof_traits> : shared_lock_proof + { + }; + } // namespace details + /// @endcond #endif //__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result.h index d87c657..f20b457 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result.h @@ -9,13 +9,13 @@ // //********************************************************* //! @file -//! WIL Error Handling Helpers: a family of macros and functions designed to uniformly handle and report errors across return -//! codes, fail fast, exceptions and logging. +//! WIL Error Handling Helpers: a family of macros and functions designed to uniformly handle and report errors across +//! return codes, fail fast, exceptions and logging. #ifndef __WIL_RESULT_INCLUDED #define __WIL_RESULT_INCLUDED -// Most functionality is picked up from result_macros.h. This file specifically provides higher level processing of errors when -// they are encountered by the underlying macros. +// Most functionality is picked up from result_macros.h. This file specifically provides higher level processing of +// errors when they are encountered by the underlying macros. #include "result_macros.h" // Note that we avoid pulling in STL's memory header from Result.h through Resource.h as we have @@ -32,1260 +32,1287 @@ #error This header is not supported in kernel-mode. #endif -// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that requests developers verify they want it +// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that +// requests developers verify they want it #pragma warning(push) #pragma warning(disable : 4351) namespace wil { -// WARNING: EVERYTHING in this namespace must be handled WITH CARE as the entities defined within -// are used as an in-proc ABI contract between binaries that utilize WIL. Making changes -// that add v-tables or change the storage semantics of anything herein needs to be done -// with care and respect to versioning. -///@cond -namespace details_abi -{ + // WARNING: EVERYTHING in this namespace must be handled WITH CARE as the entities defined within + // are used as an in-proc ABI contract between binaries that utilize WIL. Making changes + // that add v-tables or change the storage semantics of anything herein needs to be done + // with care and respect to versioning. + ///@cond + namespace details_abi + { #define __WI_SEMAHPORE_VERSION L"_p0" - // This class uses named semaphores to be able to stash a numeric value (including a pointer - // for retrieval from within any module in a process). This is a very specific need of a - // header-based library that should not be generally used. - // - // Notes for use: - // * Data members must be stable unless __WI_SEMAHPORE_VERSION is changed - // * The class must not reference module code (v-table, function pointers, etc) - // * Use of this class REQUIRES that there be a MUTEX held around the semaphore manipulation - // and tests as it doesn't attempt to handle thread contention on the semaphore while manipulating - // the count. - // * This class supports storing a 31-bit number of a single semaphore or a 62-bit number across - // two semaphores and directly supports pointers. + // This class uses named semaphores to be able to stash a numeric value (including a pointer + // for retrieval from within any module in a process). This is a very specific need of a + // header-based library that should not be generally used. + // + // Notes for use: + // * Data members must be stable unless __WI_SEMAHPORE_VERSION is changed + // * The class must not reference module code (v-table, function pointers, etc) + // * Use of this class REQUIRES that there be a MUTEX held around the semaphore manipulation + // and tests as it doesn't attempt to handle thread contention on the semaphore while manipulating + // the count. + // * This class supports storing a 31-bit number of a single semaphore or a 62-bit number across + // two semaphores and directly supports pointers. - class SemaphoreValue - { - public: - SemaphoreValue() = default; - SemaphoreValue(const SemaphoreValue&) = delete; - SemaphoreValue& operator=(const SemaphoreValue&) = delete; - - SemaphoreValue(SemaphoreValue&& other) WI_NOEXCEPT : m_semaphore(wistd::move(other.m_semaphore)), - m_semaphoreHigh(wistd::move(other.m_semaphoreHigh)) + class SemaphoreValue { - static_assert(sizeof(m_semaphore) == sizeof(HANDLE), "unique_any must be a direct representation of the HANDLE to be used across module"); - } + public: + SemaphoreValue() = default; + SemaphoreValue(const SemaphoreValue &) = delete; + SemaphoreValue &operator=(const SemaphoreValue &) = delete; - void Destroy() - { - m_semaphore.reset(); - m_semaphoreHigh.reset(); - } - - template - HRESULT CreateFromValue(PCWSTR name, T value) - { - return CreateFromValueInternal(name, (sizeof(value) > sizeof(unsigned long)), static_cast(value)); - } - - HRESULT CreateFromPointer(PCWSTR name, void* pointer) - { - ULONG_PTR value = reinterpret_cast(pointer); - FAIL_FAST_IMMEDIATE_IF(WI_IsAnyFlagSet(value, 0x3)); - return CreateFromValue(name, value >> 2); - } - - template - static HRESULT TryGetValue(PCWSTR name, _Out_ T* value, _Out_opt_ bool* retrieved = nullptr) - { - *value = static_cast(0); - unsigned __int64 value64 = 0; - __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValueInternal(name, (sizeof(T) > sizeof(unsigned long)), &value64, retrieved)); - *value = static_cast(value64); - return S_OK; - } - - static HRESULT TryGetPointer(PCWSTR name, _Outptr_result_maybenull_ void** pointer) - { - *pointer = nullptr; - ULONG_PTR value = 0; - __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValue(name, &value)); - *pointer = reinterpret_cast(value << 2); - return S_OK; - } - - private: - HRESULT CreateFromValueInternal(PCWSTR name, bool is64Bit, unsigned __int64 value) - { - WI_ASSERT(!m_semaphore && !m_semaphoreHigh); // call Destroy first - - // This routine only supports 31 bits when semahporeHigh is not supplied or 62 bits when the value - // is supplied. It's a programming error to use it when either of these conditions are not true. - - FAIL_FAST_IMMEDIATE_IF( - (!is64Bit && WI_IsAnyFlagSet(value, 0xFFFFFFFF80000000)) || (is64Bit && WI_IsAnyFlagSet(value, 0xC000000000000000))); - - wchar_t localName[MAX_PATH]; - WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); - - const unsigned long highPart = static_cast(value >> 31); - const unsigned long lowPart = static_cast(value & 0x000000007FFFFFFF); - - // We set the count of the semaphore equal to the max (the value we're storing). The only exception to that - // is ZERO, where you can't create a semaphore of value ZERO, where we push the max to one and use a count of ZERO. - - __WIL_PRIVATE_RETURN_IF_FAILED( - m_semaphore.create(static_cast(lowPart), static_cast((lowPart > 0) ? lowPart : 1), localName)); - if (is64Bit) + SemaphoreValue(SemaphoreValue &&other) WI_NOEXCEPT : m_semaphore(wistd::move(other.m_semaphore)), + m_semaphoreHigh(wistd::move(other.m_semaphoreHigh)) { - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); + static_assert(sizeof(m_semaphore) == sizeof(HANDLE), + "unique_any must be a direct representation of the HANDLE to be used across module"); + } + + void Destroy() + { + m_semaphore.reset(); + m_semaphoreHigh.reset(); + } + + template HRESULT CreateFromValue(PCWSTR name, T value) + { + return CreateFromValueInternal(name, (sizeof(value) > sizeof(unsigned long)), + static_cast(value)); + } + + HRESULT CreateFromPointer(PCWSTR name, void *pointer) + { + ULONG_PTR value = reinterpret_cast(pointer); + FAIL_FAST_IMMEDIATE_IF(WI_IsAnyFlagSet(value, 0x3)); + return CreateFromValue(name, value >> 2); + } + + template + static HRESULT TryGetValue(PCWSTR name, _Out_ T *value, _Out_opt_ bool *retrieved = nullptr) + { + *value = static_cast(0); + unsigned __int64 value64 = 0; __WIL_PRIVATE_RETURN_IF_FAILED( - m_semaphoreHigh.create(static_cast(highPart), static_cast((highPart > 0) ? highPart : 1), localName)); + TryGetValueInternal(name, (sizeof(T) > sizeof(unsigned long)), &value64, retrieved)); + *value = static_cast(value64); + return S_OK; } - return S_OK; - } - - static HRESULT GetValueFromSemaphore(HANDLE semaphore, _Out_ LONG* count) - { - // First we consume a single count from the semaphore. This will work in all cases other - // than the case where the count we've recorded is ZERO which will TIMEOUT. - - DWORD result = ::WaitForSingleObject(semaphore, 0); - __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, !((result == WAIT_OBJECT_0) || (result == WAIT_TIMEOUT))); - - LONG value = 0; - if (result == WAIT_OBJECT_0) + static HRESULT TryGetPointer(PCWSTR name, _Outptr_result_maybenull_ void **pointer) { - // We were able to wait. To establish our count, all we have to do is release that count - // back to the semaphore and observe the value that we released. - - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &value)); - value++; // we waited first, so our actual value is one more than the old value - - // Make sure the value is correct by validating that we have no more posts. - BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + *pointer = nullptr; + ULONG_PTR value = 0; + __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValue(name, &value)); + *pointer = reinterpret_cast(value << 2); + return S_OK; } - else + + private: + HRESULT CreateFromValueInternal(PCWSTR name, bool is64Bit, unsigned __int64 value) { - WI_ASSERT(result == WAIT_TIMEOUT); + WI_ASSERT(!m_semaphore && !m_semaphoreHigh); // call Destroy first - // We know at this point that the value is ZERO. We'll do some verification to ensure that - // this address is right by validating that we have one and only one more post that we could use. + // This routine only supports 31 bits when semahporeHigh is not supplied or 62 bits when the value + // is supplied. It's a programming error to use it when either of these conditions are not true. - LONG expected = 0; - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &expected)); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expected != 0); + FAIL_FAST_IMMEDIATE_IF((!is64Bit && WI_IsAnyFlagSet(value, 0xFFFFFFFF80000000)) || + (is64Bit && WI_IsAnyFlagSet(value, 0xC000000000000000))); - const BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + wchar_t localName[MAX_PATH]; + WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); - result = ::WaitForSingleObject(semaphore, 0); + const unsigned long highPart = static_cast(value >> 31); + const unsigned long lowPart = static_cast(value & 0x000000007FFFFFFF); + + // We set the count of the semaphore equal to the max (the value we're storing). The only exception to + // that is ZERO, where you can't create a semaphore of value ZERO, where we push the max to one and use + // a count of ZERO. + + __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphore.create( + static_cast(lowPart), static_cast((lowPart > 0) ? lowPart : 1), localName)); + if (is64Bit) + { + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); + __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphoreHigh.create( + static_cast(highPart), static_cast((highPart > 0) ? highPart : 1), localName)); + } + + return S_OK; + } + + static HRESULT GetValueFromSemaphore(HANDLE semaphore, _Out_ LONG *count) + { + // First we consume a single count from the semaphore. This will work in all cases other + // than the case where the count we've recorded is ZERO which will TIMEOUT. + + DWORD result = ::WaitForSingleObject(semaphore, 0); __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, result != WAIT_OBJECT_0); - } + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, !((result == WAIT_OBJECT_0) || (result == WAIT_TIMEOUT))); - *count = value; - return S_OK; - } - - static HRESULT TryGetValueInternal(PCWSTR name, bool is64Bit, _Out_ unsigned __int64* value, _Out_opt_ bool* retrieved) - { - assign_to_opt_param(retrieved, false); - *value = 0; - - wchar_t localName[MAX_PATH]; - WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); - - wil::unique_semaphore_nothrow semaphoreLow(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); - if (!semaphoreLow) - { - __WIL_PRIVATE_RETURN_HR_IF(S_OK, (::GetLastError() == ERROR_FILE_NOT_FOUND)); - __WIL_PRIVATE_RETURN_LAST_ERROR(); - } - - LONG countLow = 0; - LONG countHigh = 0; - - __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreLow.get(), &countLow)); - - if (is64Bit) - { - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); - wil::unique_semaphore_nothrow semaphoreHigh(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); - __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(semaphoreHigh); - - __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreHigh.get(), &countHigh)); - } - - WI_ASSERT((countLow >= 0) && (countHigh >= 0)); - - const unsigned __int64 newValueHigh = (static_cast(countHigh) << 31); - const unsigned __int64 newValueLow = static_cast(countLow); - - assign_to_opt_param(retrieved, true); - *value = (newValueHigh | newValueLow); - return S_OK; - } - - wil::unique_semaphore_nothrow m_semaphore; - wil::unique_semaphore_nothrow m_semaphoreHigh; - }; - - template - class ProcessLocalStorageData - { - public: - ProcessLocalStorageData(unique_mutex_nothrow&& mutex, SemaphoreValue&& value) : - m_mutex(wistd::move(mutex)), m_value(wistd::move(value)), m_data() - { - static_assert(sizeof(m_mutex) == sizeof(HANDLE), "unique_any must be equivalent to the handle size to safely use across module"); - } - - T* GetData() - { - WI_ASSERT(m_mutex); - return &m_data; - } - - void Release() - { - if (ProcessShutdownInProgress()) - { - // There are no other threads to contend with. - m_refCount = m_refCount - 1; - if (m_refCount == 0) + LONG value = 0; + if (result == WAIT_OBJECT_0) { - m_data.ProcessShutdown(); + // We were able to wait. To establish our count, all we have to do is release that count + // back to the semaphore and observe the value that we released. + + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &value)); + value++; // we waited first, so our actual value is one more than the old value + + // Make sure the value is correct by validating that we have no more posts. + BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, + expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + } + else + { + WI_ASSERT(result == WAIT_TIMEOUT); + + // We know at this point that the value is ZERO. We'll do some verification to ensure that + // this address is right by validating that we have one and only one more post that we could use. + + LONG expected = 0; + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &expected)); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expected != 0); + + const BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, + expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + + result = ::WaitForSingleObject(semaphore, 0); + __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, result != WAIT_OBJECT_0); + } + + *count = value; + return S_OK; + } + + static HRESULT TryGetValueInternal(PCWSTR name, bool is64Bit, _Out_ unsigned __int64 *value, + _Out_opt_ bool *retrieved) + { + assign_to_opt_param(retrieved, false); + *value = 0; + + wchar_t localName[MAX_PATH]; + WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); + + wil::unique_semaphore_nothrow semaphoreLow(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); + if (!semaphoreLow) + { + __WIL_PRIVATE_RETURN_HR_IF(S_OK, (::GetLastError() == ERROR_FILE_NOT_FOUND)); + __WIL_PRIVATE_RETURN_LAST_ERROR(); + } + + LONG countLow = 0; + LONG countHigh = 0; + + __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreLow.get(), &countLow)); + + if (is64Bit) + { + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); + wil::unique_semaphore_nothrow semaphoreHigh( + ::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); + __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(semaphoreHigh); + + __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreHigh.get(), &countHigh)); + } + + WI_ASSERT((countLow >= 0) && (countHigh >= 0)); + + const unsigned __int64 newValueHigh = (static_cast(countHigh) << 31); + const unsigned __int64 newValueLow = static_cast(countLow); + + assign_to_opt_param(retrieved, true); + *value = (newValueHigh | newValueLow); + return S_OK; + } + + wil::unique_semaphore_nothrow m_semaphore; + wil::unique_semaphore_nothrow m_semaphoreHigh; + }; + + template class ProcessLocalStorageData + { + public: + ProcessLocalStorageData(unique_mutex_nothrow &&mutex, SemaphoreValue &&value) + : m_mutex(wistd::move(mutex)), m_value(wistd::move(value)), m_data() + { + static_assert(sizeof(m_mutex) == sizeof(HANDLE), + "unique_any must be equivalent to the handle size to safely use across module"); + } + + T *GetData() + { + WI_ASSERT(m_mutex); + return &m_data; + } + + void Release() + { + if (ProcessShutdownInProgress()) + { + // There are no other threads to contend with. + m_refCount = m_refCount - 1; + if (m_refCount == 0) + { + m_data.ProcessShutdown(); + } + } + else + { + auto lock = m_mutex.acquire(); + m_refCount = m_refCount - 1; + if (m_refCount == 0) + { + // We must explicitly destroy our semaphores while holding the mutex + m_value.Destroy(); + lock.reset(); + + this->~ProcessLocalStorageData(); + ::HeapFree(::GetProcessHeap(), 0, this); + } } } - else - { - auto lock = m_mutex.acquire(); - m_refCount = m_refCount - 1; - if (m_refCount == 0) - { - // We must explicitly destroy our semaphores while holding the mutex - m_value.Destroy(); - lock.reset(); - this->~ProcessLocalStorageData(); - ::HeapFree(::GetProcessHeap(), 0, this); + static HRESULT Acquire(PCSTR staticNameWithVersion, + _Outptr_result_nullonfailure_ ProcessLocalStorageData **data) + { + *data = nullptr; + + // NOTE: the '0' in SM0 below is intended as the VERSION number. Changes to this class require + // that this value be revised. + + const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); + wchar_t name[MAX_PATH]; + WI_VERIFY(SUCCEEDED(StringCchPrintfW(name, ARRAYSIZE(name), L"Local\\SM0:%lu:%lu:%hs", + ::GetCurrentProcessId(), size, staticNameWithVersion))); + + unique_mutex_nothrow mutex; + mutex.reset(::CreateMutexExW(nullptr, name, 0, MUTEX_ALL_ACCESS)); + + // This will fail in some environments and will be fixed with deliverable 12394134 + RETURN_LAST_ERROR_IF_EXPECTED(!mutex); + auto lock = mutex.acquire(); + + void *pointer = nullptr; + __WIL_PRIVATE_RETURN_IF_FAILED(SemaphoreValue::TryGetPointer(name, &pointer)); + if (pointer) + { + *data = reinterpret_cast *>(pointer); + (*data)->m_refCount = (*data)->m_refCount + 1; + } + else + { + __WIL_PRIVATE_RETURN_IF_FAILED(MakeAndInitialize( + name, wistd::move(mutex), + data)); // Assumes mutex handle ownership on success ('lock' will still be released) + } + + return S_OK; + } + + private: + volatile long m_refCount = 1; + unique_mutex_nothrow m_mutex; + SemaphoreValue m_value; + T m_data; + + static HRESULT MakeAndInitialize(PCWSTR name, unique_mutex_nothrow &&mutex, + _Outptr_result_nullonfailure_ ProcessLocalStorageData **data) + { + *data = nullptr; + + const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); + + unique_process_heap_ptr dataAlloc(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, size)); + __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(dataAlloc); + + SemaphoreValue semaphoreValue; + __WIL_PRIVATE_RETURN_IF_FAILED(semaphoreValue.CreateFromPointer(name, dataAlloc.get())); + + new (dataAlloc.get()) ProcessLocalStorageData(wistd::move(mutex), wistd::move(semaphoreValue)); + *data = static_cast *>(dataAlloc.release()); + + return S_OK; + } + }; + + template class ProcessLocalStorage + { + public: + ProcessLocalStorage(PCSTR staticNameWithVersion) WI_NOEXCEPT + : m_staticNameWithVersion(staticNameWithVersion) + { + } + + ~ProcessLocalStorage() WI_NOEXCEPT + { + if (m_data) + { + m_data->Release(); } } - } - static HRESULT Acquire(PCSTR staticNameWithVersion, _Outptr_result_nullonfailure_ ProcessLocalStorageData** data) - { - *data = nullptr; - - // NOTE: the '0' in SM0 below is intended as the VERSION number. Changes to this class require - // that this value be revised. - - const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); - wchar_t name[MAX_PATH]; - WI_VERIFY(SUCCEEDED(StringCchPrintfW( - name, ARRAYSIZE(name), L"Local\\SM0:%lu:%lu:%hs", ::GetCurrentProcessId(), size, staticNameWithVersion))); - - unique_mutex_nothrow mutex; - mutex.reset(::CreateMutexExW(nullptr, name, 0, MUTEX_ALL_ACCESS)); - - // This will fail in some environments and will be fixed with deliverable 12394134 - RETURN_LAST_ERROR_IF_EXPECTED(!mutex); - auto lock = mutex.acquire(); - - void* pointer = nullptr; - __WIL_PRIVATE_RETURN_IF_FAILED(SemaphoreValue::TryGetPointer(name, &pointer)); - if (pointer) + T *GetShared() WI_NOEXCEPT { - *data = reinterpret_cast*>(pointer); - (*data)->m_refCount = (*data)->m_refCount + 1; - } - else - { - __WIL_PRIVATE_RETURN_IF_FAILED(MakeAndInitialize( - name, wistd::move(mutex), data)); // Assumes mutex handle ownership on success ('lock' will still be released) + if (!m_data) + { + ProcessLocalStorageData *localTemp = nullptr; + if (SUCCEEDED(ProcessLocalStorageData::Acquire(m_staticNameWithVersion, &localTemp)) && !m_data) + { + m_data = localTemp; + } + } + return m_data ? m_data->GetData() : nullptr; } - return S_OK; - } + private: + PCSTR m_staticNameWithVersion = nullptr; + ProcessLocalStorageData *m_data = nullptr; + }; - private: - volatile long m_refCount = 1; - unique_mutex_nothrow m_mutex; - SemaphoreValue m_value; - T m_data; - - static HRESULT MakeAndInitialize( - PCWSTR name, unique_mutex_nothrow&& mutex, _Outptr_result_nullonfailure_ ProcessLocalStorageData** data) + template class ThreadLocalStorage { - *data = nullptr; + public: + ThreadLocalStorage(const ThreadLocalStorage &) = delete; + ThreadLocalStorage &operator=(const ThreadLocalStorage &) = delete; - const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); + ThreadLocalStorage() = default; - unique_process_heap_ptr dataAlloc(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, size)); - __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(dataAlloc); + ~ThreadLocalStorage() WI_NOEXCEPT + { + for (auto &entry : m_hashArray) + { + Node *pNode = entry; + while (pNode != nullptr) + { + auto pCurrent = pNode; +#pragma warning(push) +#pragma warning(disable : 6001) // https://github.com/microsoft/wil/issues/164 + pNode = pNode->pNext; +#pragma warning(pop) + pCurrent->~Node(); + ::HeapFree(::GetProcessHeap(), 0, pCurrent); + } + entry = nullptr; + } + } - SemaphoreValue semaphoreValue; - __WIL_PRIVATE_RETURN_IF_FAILED(semaphoreValue.CreateFromPointer(name, dataAlloc.get())); + // Note: Can return nullptr even when (shouldAllocate == true) upon allocation failure + T *GetLocal(bool shouldAllocate = false) WI_NOEXCEPT + { + DWORD const threadId = ::GetCurrentThreadId(); + size_t const index = (threadId % ARRAYSIZE(m_hashArray)); + for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext) + { + if (pNode->threadId == threadId) + { + return &pNode->value; + } + } - new (dataAlloc.get()) ProcessLocalStorageData(wistd::move(mutex), wistd::move(semaphoreValue)); - *data = static_cast*>(dataAlloc.release()); + if (shouldAllocate) + { + if (auto pNewRaw = details::ProcessHeapAlloc(0, sizeof(Node))) + { + auto pNew = new (pNewRaw) Node{threadId}; - return S_OK; + Node *pFirst; + do + { + pFirst = m_hashArray[index]; + pNew->pNext = pFirst; + } while (::InterlockedCompareExchangePointer( + reinterpret_cast(m_hashArray + index), pNew, pFirst) != pFirst); + + return &pNew->value; + } + } + return nullptr; + } + + private: + struct Node + { + DWORD threadId = 0xffffffffu; + Node *pNext = nullptr; + T value{}; + }; + + Node *volatile m_hashArray[10]{}; + }; + + struct ThreadLocalFailureInfo + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size; + unsigned char reserved1[2]; // packing, reserved + // When this failure was seen + unsigned int sequenceId; + + // Information about the failure + HRESULT hr; + PCSTR fileName; + unsigned short lineNumber; + unsigned char failureType; // FailureType + unsigned char reserved2; // packing, reserved + PCSTR modulePath; + void *returnAddress; + void *callerReturnAddress; + PCWSTR message; + + // The allocation (LocalAlloc) where structure strings point + void *stringBuffer; + size_t stringBufferSize; + + // NOTE: Externally Managed: Must not have constructor or destructor + + void Clear() + { + ::HeapFree(::GetProcessHeap(), 0, stringBuffer); + stringBuffer = nullptr; + stringBufferSize = 0; + } + + void Set(const FailureInfo &info, unsigned int newSequenceId) + { + sequenceId = newSequenceId; + + hr = info.hr; + fileName = nullptr; + lineNumber = static_cast(info.uLineNumber); + failureType = static_cast(info.type); + modulePath = nullptr; + returnAddress = info.returnAddress; + callerReturnAddress = info.callerReturnAddress; + message = nullptr; + + size_t neededSize = details::ResultStringSize(info.pszFile) + + details::ResultStringSize(info.pszModule) + + details::ResultStringSize(info.pszMessage); + + if (!stringBuffer || (stringBufferSize < neededSize)) + { + auto newBuffer = details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, neededSize); + if (newBuffer) + { + ::HeapFree(::GetProcessHeap(), 0, stringBuffer); + stringBuffer = newBuffer; + stringBufferSize = neededSize; + } + } + + if (stringBuffer) + { + unsigned char *pBuffer = static_cast(stringBuffer); + unsigned char *pBufferEnd = pBuffer + stringBufferSize; + + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszFile, &fileName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszModule, &modulePath); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszMessage, &message); + ZeroMemory(pBuffer, pBufferEnd - pBuffer); + } + } + + void Get(FailureInfo &info) const + { + ::ZeroMemory(&info, sizeof(info)); + + info.failureId = sequenceId; + info.hr = hr; + info.pszFile = fileName; + info.uLineNumber = lineNumber; + info.type = static_cast(failureType); + info.pszModule = modulePath; + info.returnAddress = returnAddress; + info.callerReturnAddress = callerReturnAddress; + info.pszMessage = message; + } + }; + + struct ThreadLocalData + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size = sizeof(ThreadLocalData); + + // Subscription information + unsigned int threadId = 0; + volatile long *failureSequenceId = nullptr; // backpointer to the global ID + + // Information about thread errors + unsigned int latestSubscribedFailureSequenceId = 0; + + // The last (N) observed errors + ThreadLocalFailureInfo *errors = nullptr; + unsigned short errorAllocCount = 0; + unsigned short errorCurrentIndex = 0; + + // NOTE: Externally Managed: Must allow ZERO init construction + + ~ThreadLocalData() + { + Clear(); + } + + void Clear() + { + for (auto &error : make_range(errors, errorAllocCount)) + { + error.Clear(); + } + ::HeapFree(::GetProcessHeap(), 0, errors); + errorAllocCount = 0; + errorCurrentIndex = 0; + errors = nullptr; + } + + bool EnsureAllocated(bool create = true) + { + if (!errors && create) + { + const unsigned short errorCount = 5; + errors = reinterpret_cast( + details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo))); + if (errors) + { + errorAllocCount = errorCount; + errorCurrentIndex = 0; + for (auto &error : make_range(errors, errorAllocCount)) + { + error.size = sizeof(ThreadLocalFailureInfo); + } + } + } + return (errors != nullptr); + } + + void SetLastError(const wil::FailureInfo &info) + { + const bool hasListener = (latestSubscribedFailureSequenceId > 0); + + if (!EnsureAllocated(hasListener)) + { + // We either couldn't allocate or we haven't yet allocated and nobody + // was listening, so we ignore. + return; + } + + if (hasListener) + { + // When we have listeners, we can throw away any updates to the last seen error + // code within the same listening context presuming it's an update of the existing + // error with the same code. + + for (auto &error : make_range(errors, errorAllocCount)) + { + if ((error.sequenceId > latestSubscribedFailureSequenceId) && (error.hr == info.hr)) + { + return; + } + } + } + + // Otherwise we create a new failure... + + errorCurrentIndex = (errorCurrentIndex + 1) % errorAllocCount; + errors[errorCurrentIndex].Set(info, ::InterlockedIncrementNoFence(failureSequenceId)); + } + + WI_NODISCARD bool GetLastError(_Inout_ wil::FailureInfo &info, unsigned int minSequenceId, + HRESULT matchRequirement) const + { + if (!errors) + { + return false; + } + + // If the last error we saw doesn't meet the filter requirement or if the last error was never + // set, then we couldn't return a result at all... + auto &lastFailure = errors[errorCurrentIndex]; + if (minSequenceId >= lastFailure.sequenceId) + { + return false; + } + + // With no result filter, we just go to the last error and report it + if (matchRequirement == S_OK) + { + lastFailure.Get(info); + return true; + } + + // Find the oldest result matching matchRequirement and passing minSequenceId + ThreadLocalFailureInfo *find = nullptr; + for (auto &error : make_range(errors, errorAllocCount)) + { + if ((error.hr == matchRequirement) && (error.sequenceId > minSequenceId)) + { + if (!find || (error.sequenceId < find->sequenceId)) + { + find = &error; + } + } + } + if (find) + { + find->Get(info); + return true; + } + + return false; + } + + bool GetCaughtExceptionError(_Inout_ wil::FailureInfo &info, unsigned int minSequenceId, + _In_opt_ const DiagnosticsInfo *diagnostics, HRESULT matchRequirement, + void *returnAddress) + { + // First attempt to get the last error and then see if it matches the error returned from + // the last caught exception. If it does, then we're good to go and we return that last error. + + FailureInfo last = {}; + if (GetLastError(last, minSequenceId, matchRequirement) && (last.hr == ResultFromCaughtException())) + { + info = last; + return true; + } + + // The last error didn't match or we never had one... we need to create one -- we do so by logging + // our current request and then using the last error. + + DiagnosticsInfo source; + if (diagnostics) + { + source = *diagnostics; + } + + // NOTE: FailureType::Log as it's only informative (no action) and SupportedExceptions::All as it's not + // a barrier, only recognition. + wchar_t message[2048]{}; + const HRESULT hr = details::ReportFailure_CaughtExceptionCommon( + __R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), + SupportedExceptions::All) + .hr; + + // Now that the exception was logged, we should be able to fetch it. + return GetLastError(info, minSequenceId, hr); + } + }; + + struct ProcessLocalData + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size = sizeof(ProcessLocalData); + + // Failure Information + volatile long failureSequenceId = 1; // process global variable + ThreadLocalStorage threads; // list of allocated threads + + void ProcessShutdown() + { + } + }; + + __declspec(selectany) ProcessLocalStorage *g_pProcessLocalData = nullptr; + + __declspec(noinline) inline ThreadLocalData *GetThreadLocalDataCache(bool allocate = true) + { + ThreadLocalData *result = nullptr; + if (g_pProcessLocalData) + { + auto processData = g_pProcessLocalData->GetShared(); + if (processData) + { + result = processData->threads.GetLocal(allocate); + if (result && !result->failureSequenceId) + { + result->failureSequenceId = &(processData->failureSequenceId); + } + } + } + return result; } - }; - template - class ProcessLocalStorage + __forceinline ThreadLocalData *GetThreadLocalData(bool allocate = true) + { + return GetThreadLocalDataCache(allocate); + } + + } // namespace details_abi + /// @endcond + + /** Returns a sequence token that can be used with wil::GetLastError to limit errors to those that occur after this + token was retrieved. General usage pattern: use wil::GetCurrentErrorSequenceId to cache a token, execute your code, + on failure use wil::GetLastError with the token to provide information on the error that occurred while executing + your code. Prefer to use wil::ThreadErrorContext over this approach when possible. */ + inline long GetCurrentErrorSequenceId() { - public: - ProcessLocalStorage(PCSTR staticNameWithVersion) WI_NOEXCEPT : m_staticNameWithVersion(staticNameWithVersion) + auto data = details_abi::GetThreadLocalData(); + if (data) { + // someone is interested -- make sure we can store errors + data->EnsureAllocated(); + return *data->failureSequenceId; } - ~ProcessLocalStorage() WI_NOEXCEPT + return 0; + } + + /** Caches failure information for later retrieval from GetLastError. + Most people will never need to do this explicitly as failure information is automatically made available per-thread + across a process when errors are encountered naturally through the WIL macros. */ + inline void SetLastError(const wil::FailureInfo &info) + { + static volatile unsigned int lastThread = 0; + auto threadId = ::GetCurrentThreadId(); + if (lastThread != threadId) + { + static volatile long depth = 0; + if (::InterlockedIncrementNoFence(&depth) < 4) + { + lastThread = threadId; + auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present + if (data) + { + data->SetLastError(info); + } + lastThread = 0; + } + ::InterlockedDecrementNoFence(&depth); + } + } + + /** Retrieves failure information for the current thread with the given filters. + This API can be used to retrieve information about the last WIL failure that occurred on the current thread. + This error crosses DLL boundaries as long as the error occurred in the current process. Passing a minSequenceId + restricts the error returned to one that occurred after the given sequence ID. Passing matchRequirement also + filters the returned result to the given error code. */ + inline bool GetLastError(_Inout_ wil::FailureInfo &info, unsigned int minSequenceId = 0, + HRESULT matchRequirement = S_OK) + { + auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present + if (data) + { + return data->GetLastError(info, minSequenceId, matchRequirement); + } + return false; + } + + /** Retrieves failure information when within a catch block for the current thread with the given filters. + When unable to retrieve the exception information (when WIL hasn't yet seen it), this will attempt (best effort) to + discover information about the exception and will attribute that information to the given DiagnosticsInfo position. + See GetLastError for capabilities and filtering. */ + inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo &info, + unsigned int minSequenceId = 0, + const DiagnosticsInfo *diagnostics = nullptr, + HRESULT matchRequirement = S_OK) + { + auto data = details_abi::GetThreadLocalData(); + if (data) + { + return data->GetCaughtExceptionError(info, minSequenceId, diagnostics, matchRequirement, _ReturnAddress()); + } + return false; + } + + /** Use this class to manage retrieval of information about an error occurring in the requested code. + Construction of this class sets a point in time after which you can use the GetLastError class method to retrieve + the origination of the last error that occurred on this thread since the class was created. */ + class ThreadErrorContext + { + public: + ThreadErrorContext() : m_data(details_abi::GetThreadLocalData()) { if (m_data) { - m_data->Release(); + m_sequenceIdLast = m_data->latestSubscribedFailureSequenceId; + m_sequenceIdStart = *m_data->failureSequenceId; + m_data->latestSubscribedFailureSequenceId = m_sequenceIdStart; } } - T* GetShared() WI_NOEXCEPT + ~ThreadErrorContext() { - if (!m_data) + if (m_data) { - ProcessLocalStorageData* localTemp = nullptr; - if (SUCCEEDED(ProcessLocalStorageData::Acquire(m_staticNameWithVersion, &localTemp)) && !m_data) - { - m_data = localTemp; - } - } - return m_data ? m_data->GetData() : nullptr; - } - - private: - PCSTR m_staticNameWithVersion = nullptr; - ProcessLocalStorageData* m_data = nullptr; - }; - - template - class ThreadLocalStorage - { - public: - ThreadLocalStorage(const ThreadLocalStorage&) = delete; - ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete; - - ThreadLocalStorage() = default; - - ~ThreadLocalStorage() WI_NOEXCEPT - { - for (auto& entry : m_hashArray) - { - Node* pNode = entry; - while (pNode != nullptr) - { - auto pCurrent = pNode; -#pragma warning(push) -#pragma warning(disable : 6001) // https://github.com/microsoft/wil/issues/164 - pNode = pNode->pNext; -#pragma warning(pop) - pCurrent->~Node(); - ::HeapFree(::GetProcessHeap(), 0, pCurrent); - } - entry = nullptr; + m_data->latestSubscribedFailureSequenceId = m_sequenceIdLast; } } - // Note: Can return nullptr even when (shouldAllocate == true) upon allocation failure - T* GetLocal(bool shouldAllocate = false) WI_NOEXCEPT + /** Retrieves the origination of the last error that occurred since this class was constructed. + The optional parameter allows the failure information returned to be filtered to a specific + result. */ + inline bool GetLastError(FailureInfo &info, HRESULT matchRequirement = S_OK) { - DWORD const threadId = ::GetCurrentThreadId(); - size_t const index = (threadId % ARRAYSIZE(m_hashArray)); - for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext) + if (m_data) { - if (pNode->threadId == threadId) - { - return &pNode->value; - } + return m_data->GetLastError(info, m_sequenceIdStart, matchRequirement); } - - if (shouldAllocate) - { - if (auto pNewRaw = details::ProcessHeapAlloc(0, sizeof(Node))) - { - auto pNew = new (pNewRaw) Node{threadId}; - - Node* pFirst; - do - { - pFirst = m_hashArray[index]; - pNew->pNext = pFirst; - } while (::InterlockedCompareExchangePointer(reinterpret_cast(m_hashArray + index), pNew, pFirst) != - pFirst); - - return &pNew->value; - } - } - return nullptr; - } - - private: - struct Node - { - DWORD threadId = 0xffffffffu; - Node* pNext = nullptr; - T value{}; - }; - - Node* volatile m_hashArray[10]{}; - }; - - struct ThreadLocalFailureInfo - { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size; - unsigned char reserved1[2]; // packing, reserved - // When this failure was seen - unsigned int sequenceId; - - // Information about the failure - HRESULT hr; - PCSTR fileName; - unsigned short lineNumber; - unsigned char failureType; // FailureType - unsigned char reserved2; // packing, reserved - PCSTR modulePath; - void* returnAddress; - void* callerReturnAddress; - PCWSTR message; - - // The allocation (LocalAlloc) where structure strings point - void* stringBuffer; - size_t stringBufferSize; - - // NOTE: Externally Managed: Must not have constructor or destructor - - void Clear() - { - ::HeapFree(::GetProcessHeap(), 0, stringBuffer); - stringBuffer = nullptr; - stringBufferSize = 0; - } - - void Set(const FailureInfo& info, unsigned int newSequenceId) - { - sequenceId = newSequenceId; - - hr = info.hr; - fileName = nullptr; - lineNumber = static_cast(info.uLineNumber); - failureType = static_cast(info.type); - modulePath = nullptr; - returnAddress = info.returnAddress; - callerReturnAddress = info.callerReturnAddress; - message = nullptr; - - size_t neededSize = details::ResultStringSize(info.pszFile) + details::ResultStringSize(info.pszModule) + - details::ResultStringSize(info.pszMessage); - - if (!stringBuffer || (stringBufferSize < neededSize)) - { - auto newBuffer = details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, neededSize); - if (newBuffer) - { - ::HeapFree(::GetProcessHeap(), 0, stringBuffer); - stringBuffer = newBuffer; - stringBufferSize = neededSize; - } - } - - if (stringBuffer) - { - unsigned char* pBuffer = static_cast(stringBuffer); - unsigned char* pBufferEnd = pBuffer + stringBufferSize; - - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszFile, &fileName); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszModule, &modulePath); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszMessage, &message); - ZeroMemory(pBuffer, pBufferEnd - pBuffer); - } - } - - void Get(FailureInfo& info) const - { - ::ZeroMemory(&info, sizeof(info)); - - info.failureId = sequenceId; - info.hr = hr; - info.pszFile = fileName; - info.uLineNumber = lineNumber; - info.type = static_cast(failureType); - info.pszModule = modulePath; - info.returnAddress = returnAddress; - info.callerReturnAddress = callerReturnAddress; - info.pszMessage = message; - } - }; - - struct ThreadLocalData - { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size = sizeof(ThreadLocalData); - - // Subscription information - unsigned int threadId = 0; - volatile long* failureSequenceId = nullptr; // backpointer to the global ID - - // Information about thread errors - unsigned int latestSubscribedFailureSequenceId = 0; - - // The last (N) observed errors - ThreadLocalFailureInfo* errors = nullptr; - unsigned short errorAllocCount = 0; - unsigned short errorCurrentIndex = 0; - - // NOTE: Externally Managed: Must allow ZERO init construction - - ~ThreadLocalData() - { - Clear(); - } - - void Clear() - { - for (auto& error : make_range(errors, errorAllocCount)) - { - error.Clear(); - } - ::HeapFree(::GetProcessHeap(), 0, errors); - errorAllocCount = 0; - errorCurrentIndex = 0; - errors = nullptr; - } - - bool EnsureAllocated(bool create = true) - { - if (!errors && create) - { - const unsigned short errorCount = 5; - errors = reinterpret_cast( - details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo))); - if (errors) - { - errorAllocCount = errorCount; - errorCurrentIndex = 0; - for (auto& error : make_range(errors, errorAllocCount)) - { - error.size = sizeof(ThreadLocalFailureInfo); - } - } - } - return (errors != nullptr); - } - - void SetLastError(const wil::FailureInfo& info) - { - const bool hasListener = (latestSubscribedFailureSequenceId > 0); - - if (!EnsureAllocated(hasListener)) - { - // We either couldn't allocate or we haven't yet allocated and nobody - // was listening, so we ignore. - return; - } - - if (hasListener) - { - // When we have listeners, we can throw away any updates to the last seen error - // code within the same listening context presuming it's an update of the existing - // error with the same code. - - for (auto& error : make_range(errors, errorAllocCount)) - { - if ((error.sequenceId > latestSubscribedFailureSequenceId) && (error.hr == info.hr)) - { - return; - } - } - } - - // Otherwise we create a new failure... - - errorCurrentIndex = (errorCurrentIndex + 1) % errorAllocCount; - errors[errorCurrentIndex].Set(info, ::InterlockedIncrementNoFence(failureSequenceId)); - } - - WI_NODISCARD bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, HRESULT matchRequirement) const - { - if (!errors) - { - return false; - } - - // If the last error we saw doesn't meet the filter requirement or if the last error was never - // set, then we couldn't return a result at all... - auto& lastFailure = errors[errorCurrentIndex]; - if (minSequenceId >= lastFailure.sequenceId) - { - return false; - } - - // With no result filter, we just go to the last error and report it - if (matchRequirement == S_OK) - { - lastFailure.Get(info); - return true; - } - - // Find the oldest result matching matchRequirement and passing minSequenceId - ThreadLocalFailureInfo* find = nullptr; - for (auto& error : make_range(errors, errorAllocCount)) - { - if ((error.hr == matchRequirement) && (error.sequenceId > minSequenceId)) - { - if (!find || (error.sequenceId < find->sequenceId)) - { - find = &error; - } - } - } - if (find) - { - find->Get(info); - return true; - } - return false; } - bool GetCaughtExceptionError( - _Inout_ wil::FailureInfo& info, - unsigned int minSequenceId, - _In_opt_ const DiagnosticsInfo* diagnostics, - HRESULT matchRequirement, - void* returnAddress) + /** Retrieves the origin of the current exception (within a catch block) since this class was constructed. + See @ref GetCaughtExceptionError for more information */ + inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo &info, + const DiagnosticsInfo *diagnostics = nullptr, + HRESULT matchRequirement = S_OK) { - // First attempt to get the last error and then see if it matches the error returned from - // the last caught exception. If it does, then we're good to go and we return that last error. - - FailureInfo last = {}; - if (GetLastError(last, minSequenceId, matchRequirement) && (last.hr == ResultFromCaughtException())) + if (m_data) { - info = last; - return true; + return m_data->GetCaughtExceptionError(info, m_sequenceIdStart, diagnostics, matchRequirement, + _ReturnAddress()); } - - // The last error didn't match or we never had one... we need to create one -- we do so by logging - // our current request and then using the last error. - - DiagnosticsInfo source; - if (diagnostics) - { - source = *diagnostics; - } - - // NOTE: FailureType::Log as it's only informative (no action) and SupportedExceptions::All as it's not a barrier, only recognition. - wchar_t message[2048]{}; - const HRESULT hr = details::ReportFailure_CaughtExceptionCommon( - __R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), SupportedExceptions::All) - .hr; - - // Now that the exception was logged, we should be able to fetch it. - return GetLastError(info, minSequenceId, hr); + return false; } + + private: + details_abi::ThreadLocalData *m_data; + unsigned long m_sequenceIdStart{}; + unsigned long m_sequenceIdLast{}; }; - struct ProcessLocalData + enum class WilInitializeCommand { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size = sizeof(ProcessLocalData); - - // Failure Information - volatile long failureSequenceId = 1; // process global variable - ThreadLocalStorage threads; // list of allocated threads - - void ProcessShutdown() - { - } + Create, + Destroy, }; - __declspec(selectany) ProcessLocalStorage* g_pProcessLocalData = nullptr; - - __declspec(noinline) inline ThreadLocalData* GetThreadLocalDataCache(bool allocate = true) + /// @cond + namespace details { - ThreadLocalData* result = nullptr; - if (g_pProcessLocalData) + struct IFailureCallback { - auto processData = g_pProcessLocalData->GetShared(); - if (processData) + virtual bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT = 0; + }; + + class ThreadFailureCallbackHolder; + + __declspec(selectany) details_abi::ThreadLocalStorage + *g_pThreadFailureCallbacks = nullptr; + + class ThreadFailureCallbackHolder + { + public: + ThreadFailureCallbackHolder(_In_opt_ IFailureCallback *pCallbackParam, + _In_opt_ CallContextInfo *pCallContext = nullptr, + bool watchNow = true) WI_NOEXCEPT : m_ppThreadList(nullptr), + m_pCallback(pCallbackParam), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(pCallContext) { - result = processData->threads.GetLocal(allocate); - if (result && !result->failureSequenceId) + if (watchNow) { - result->failureSequenceId = &(processData->failureSequenceId); + StartWatching(); } } - } - return result; - } - __forceinline ThreadLocalData* GetThreadLocalData(bool allocate = true) - { - return GetThreadLocalDataCache(allocate); - } - -} // namespace details_abi -/// @endcond - -/** Returns a sequence token that can be used with wil::GetLastError to limit errors to those that occur after this token was -retrieved. General usage pattern: use wil::GetCurrentErrorSequenceId to cache a token, execute your code, on failure use -wil::GetLastError with the token to provide information on the error that occurred while executing your code. Prefer to use -wil::ThreadErrorContext over this approach when possible. */ -inline long GetCurrentErrorSequenceId() -{ - auto data = details_abi::GetThreadLocalData(); - if (data) - { - // someone is interested -- make sure we can store errors - data->EnsureAllocated(); - return *data->failureSequenceId; - } - - return 0; -} - -/** Caches failure information for later retrieval from GetLastError. -Most people will never need to do this explicitly as failure information is automatically made available per-thread across a -process when errors are encountered naturally through the WIL macros. */ -inline void SetLastError(const wil::FailureInfo& info) -{ - static volatile unsigned int lastThread = 0; - auto threadId = ::GetCurrentThreadId(); - if (lastThread != threadId) - { - static volatile long depth = 0; - if (::InterlockedIncrementNoFence(&depth) < 4) - { - lastThread = threadId; - auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present - if (data) + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder &&other) WI_NOEXCEPT + : m_ppThreadList(nullptr), + m_pCallback(other.m_pCallback), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(other.m_pCallContext) { - data->SetLastError(info); - } - lastThread = 0; - } - ::InterlockedDecrementNoFence(&depth); - } -} - -/** Retrieves failure information for the current thread with the given filters. -This API can be used to retrieve information about the last WIL failure that occurred on the current thread. -This error crosses DLL boundaries as long as the error occurred in the current process. Passing a minSequenceId -restricts the error returned to one that occurred after the given sequence ID. Passing matchRequirement also filters -the returned result to the given error code. */ -inline bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, HRESULT matchRequirement = S_OK) -{ - auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present - if (data) - { - return data->GetLastError(info, minSequenceId, matchRequirement); - } - return false; -} - -/** Retrieves failure information when within a catch block for the current thread with the given filters. -When unable to retrieve the exception information (when WIL hasn't yet seen it), this will attempt (best effort) to -discover information about the exception and will attribute that information to the given DiagnosticsInfo position. -See GetLastError for capabilities and filtering. */ -inline __declspec(noinline) bool GetCaughtExceptionError( - _Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) -{ - auto data = details_abi::GetThreadLocalData(); - if (data) - { - return data->GetCaughtExceptionError(info, minSequenceId, diagnostics, matchRequirement, _ReturnAddress()); - } - return false; -} - -/** Use this class to manage retrieval of information about an error occurring in the requested code. -Construction of this class sets a point in time after which you can use the GetLastError class method to retrieve -the origination of the last error that occurred on this thread since the class was created. */ -class ThreadErrorContext -{ -public: - ThreadErrorContext() : m_data(details_abi::GetThreadLocalData()) - { - if (m_data) - { - m_sequenceIdLast = m_data->latestSubscribedFailureSequenceId; - m_sequenceIdStart = *m_data->failureSequenceId; - m_data->latestSubscribedFailureSequenceId = m_sequenceIdStart; - } - } - - ~ThreadErrorContext() - { - if (m_data) - { - m_data->latestSubscribedFailureSequenceId = m_sequenceIdLast; - } - } - - /** Retrieves the origination of the last error that occurred since this class was constructed. - The optional parameter allows the failure information returned to be filtered to a specific - result. */ - inline bool GetLastError(FailureInfo& info, HRESULT matchRequirement = S_OK) - { - if (m_data) - { - return m_data->GetLastError(info, m_sequenceIdStart, matchRequirement); - } - return false; - } - - /** Retrieves the origin of the current exception (within a catch block) since this class was constructed. - See @ref GetCaughtExceptionError for more information */ - inline __declspec(noinline) bool GetCaughtExceptionError( - _Inout_ wil::FailureInfo& info, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) - { - if (m_data) - { - return m_data->GetCaughtExceptionError(info, m_sequenceIdStart, diagnostics, matchRequirement, _ReturnAddress()); - } - return false; - } - -private: - details_abi::ThreadLocalData* m_data; - unsigned long m_sequenceIdStart{}; - unsigned long m_sequenceIdLast{}; -}; - -enum class WilInitializeCommand -{ - Create, - Destroy, -}; - -/// @cond -namespace details -{ - struct IFailureCallback - { - virtual bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT = 0; - }; - - class ThreadFailureCallbackHolder; - - __declspec(selectany) details_abi::ThreadLocalStorage* g_pThreadFailureCallbacks = nullptr; - - class ThreadFailureCallbackHolder - { - public: - ThreadFailureCallbackHolder( - _In_opt_ IFailureCallback* pCallbackParam, _In_opt_ CallContextInfo* pCallContext = nullptr, bool watchNow = true) WI_NOEXCEPT - : m_ppThreadList(nullptr), - m_pCallback(pCallbackParam), - m_pNext(nullptr), - m_threadId(0), - m_pCallContext(pCallContext) - { - if (watchNow) - { - StartWatching(); - } - } - - ThreadFailureCallbackHolder(ThreadFailureCallbackHolder&& other) WI_NOEXCEPT : m_ppThreadList(nullptr), - m_pCallback(other.m_pCallback), - m_pNext(nullptr), - m_threadId(0), - m_pCallContext(other.m_pCallContext) - { - if (other.m_threadId != 0) - { - other.StopWatching(); - StartWatching(); - } - } - - ~ThreadFailureCallbackHolder() WI_NOEXCEPT - { - if (m_threadId != 0) - { - StopWatching(); - } - } - - void SetCallContext(_In_opt_ CallContextInfo* pCallContext) - { - m_pCallContext = pCallContext; - } - - CallContextInfo* CallContextInfo() - { - return m_pCallContext; - } - - void StartWatching() - { - // out-of balance Start/Stop calls? - __FAIL_FAST_IMMEDIATE_ASSERT__(m_threadId == 0); - - m_ppThreadList = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal(true) - : nullptr; // true = allocate thread list if missing - if (m_ppThreadList) - { - m_pNext = *m_ppThreadList; - *m_ppThreadList = this; - m_threadId = ::GetCurrentThreadId(); - } - } - - void StopWatching() - { - if (m_threadId != ::GetCurrentThreadId()) - { - // The thread-specific failure holder cannot be stopped on a different thread than it was started on or the - // internal book-keeping list will be corrupted. To fix this change the telemetry pattern in the calling code - // to match one of the patterns available here: - // https://microsoft.sharepoint.com/teams/osg_development/Shared%20Documents/Windows%20TraceLogging%20Helpers.docx - - WI_USAGE_ERROR("MEMORY CORRUPTION: Calling code is leaking an activity thread-watcher and releasing it on another thread"); - } - - m_threadId = 0; - - while (*m_ppThreadList != nullptr) - { - if (*m_ppThreadList == this) + if (other.m_threadId != 0) { - *m_ppThreadList = m_pNext; - break; + other.StopWatching(); + StartWatching(); } - m_ppThreadList = &((*m_ppThreadList)->m_pNext); } - m_ppThreadList = nullptr; - } - WI_NODISCARD bool IsWatching() const - { - return (m_threadId != 0); - } - - void SetWatching(bool shouldWatch) - { - if (shouldWatch && !IsWatching()) + ~ThreadFailureCallbackHolder() WI_NOEXCEPT { - StartWatching(); - } - else if (!shouldWatch && IsWatching()) - { - StopWatching(); - } - } - - static bool GetThreadContext( - _Inout_ FailureInfo* pFailure, - _In_opt_ ThreadFailureCallbackHolder* pCallback, - _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) - { - *callContextString = '\0'; - bool foundContext = false; - if (pCallback != nullptr) - { - foundContext = GetThreadContext(pFailure, pCallback->m_pNext, callContextString, callContextStringLength); - - if (pCallback->m_pCallContext != nullptr) + if (m_threadId != 0) { - auto& context = *pCallback->m_pCallContext; + StopWatching(); + } + } - // We generate the next telemetry ID only when we've found an error (avoid always incrementing) - if (context.contextId == 0) + void SetCallContext(_In_opt_ CallContextInfo *pCallContext) + { + m_pCallContext = pCallContext; + } + + CallContextInfo *CallContextInfo() + { + return m_pCallContext; + } + + void StartWatching() + { + // out-of balance Start/Stop calls? + __FAIL_FAST_IMMEDIATE_ASSERT__(m_threadId == 0); + + m_ppThreadList = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal(true) + : nullptr; // true = allocate thread list if missing + if (m_ppThreadList) + { + m_pNext = *m_ppThreadList; + *m_ppThreadList = this; + m_threadId = ::GetCurrentThreadId(); + } + } + + void StopWatching() + { + if (m_threadId != ::GetCurrentThreadId()) + { + // The thread-specific failure holder cannot be stopped on a different thread than it was started on + // or the internal book-keeping list will be corrupted. To fix this change the telemetry pattern in + // the calling code to match one of the patterns available here: + // https://microsoft.sharepoint.com/teams/osg_development/Shared%20Documents/Windows%20TraceLogging%20Helpers.docx + + WI_USAGE_ERROR("MEMORY CORRUPTION: Calling code is leaking an activity thread-watcher and " + "releasing it on another thread"); + } + + m_threadId = 0; + + while (*m_ppThreadList != nullptr) + { + if (*m_ppThreadList == this) { - context.contextId = ::InterlockedIncrementNoFence(&s_telemetryId); + *m_ppThreadList = m_pNext; + break; + } + m_ppThreadList = &((*m_ppThreadList)->m_pNext); + } + m_ppThreadList = nullptr; + } + + WI_NODISCARD bool IsWatching() const + { + return (m_threadId != 0); + } + + void SetWatching(bool shouldWatch) + { + if (shouldWatch && !IsWatching()) + { + StartWatching(); + } + else if (!shouldWatch && IsWatching()) + { + StopWatching(); + } + } + + static bool GetThreadContext(_Inout_ FailureInfo *pFailure, _In_opt_ ThreadFailureCallbackHolder *pCallback, + _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) + { + *callContextString = '\0'; + bool foundContext = false; + if (pCallback != nullptr) + { + foundContext = + GetThreadContext(pFailure, pCallback->m_pNext, callContextString, callContextStringLength); + + if (pCallback->m_pCallContext != nullptr) + { + auto &context = *pCallback->m_pCallContext; + + // We generate the next telemetry ID only when we've found an error (avoid always incrementing) + if (context.contextId == 0) + { + context.contextId = ::InterlockedIncrementNoFence(&s_telemetryId); + } + + if (pFailure->callContextOriginating.contextId == 0) + { + pFailure->callContextOriginating = context; + } + + pFailure->callContextCurrent = context; + + auto callContextStringEnd = callContextString + callContextStringLength; + callContextString += strlen(callContextString); + + if ((callContextStringEnd - callContextString) > 2) // room for at least the slash + null + { + *callContextString++ = '\\'; + auto nameSizeBytes = strlen(context.contextName) + 1; + size_t remainingBytes = static_cast(callContextStringEnd - callContextString); + auto copyBytes = (nameSizeBytes < remainingBytes) ? nameSizeBytes : remainingBytes; + memcpy_s(callContextString, remainingBytes, context.contextName, copyBytes); + *(callContextString + (copyBytes - 1)) = '\0'; + } + + return true; + } + } + return foundContext; + } + + static void GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, + _Out_writes_(callContextStringLength) + _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringLength > 0) + size_t callContextStringLength) WI_NOEXCEPT + { + *callContextString = '\0'; + bool reportedTelemetry = false; + + ThreadFailureCallbackHolder **ppListeners = + g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal() : nullptr; + if ((ppListeners != nullptr) && (*ppListeners != nullptr)) + { + callContextString[0] = '\0'; + if (GetThreadContext(pFailure, *ppListeners, callContextString, callContextStringLength)) + { + pFailure->pszCallContext = callContextString; } - if (pFailure->callContextOriginating.contextId == 0) + auto pNode = *ppListeners; + do { - pFailure->callContextOriginating = context; - } + reportedTelemetry |= pNode->m_pCallback->NotifyFailure(*pFailure); + pNode = pNode->m_pNext; + } while (pNode != nullptr); + } - pFailure->callContextCurrent = context; - - auto callContextStringEnd = callContextString + callContextStringLength; - callContextString += strlen(callContextString); - - if ((callContextStringEnd - callContextString) > 2) // room for at least the slash + null - { - *callContextString++ = '\\'; - auto nameSizeBytes = strlen(context.contextName) + 1; - size_t remainingBytes = static_cast(callContextStringEnd - callContextString); - auto copyBytes = (nameSizeBytes < remainingBytes) ? nameSizeBytes : remainingBytes; - memcpy_s(callContextString, remainingBytes, context.contextName, copyBytes); - *(callContextString + (copyBytes - 1)) = '\0'; - } - - return true; + if (g_pfnTelemetryCallback != nullptr) + { + // If the telemetry was requested to be suppressed, + // pretend like it has already been reported to the fallback callback + g_pfnTelemetryCallback(reportedTelemetry || + WI_IsFlagSet(pFailure->flags, FailureFlags::RequestSuppressTelemetry), + *pFailure); } } - return foundContext; - } - static void GetContextAndNotifyFailure( - _Inout_ FailureInfo* pFailure, - _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder const &) = delete; + ThreadFailureCallbackHolder &operator=(ThreadFailureCallbackHolder const &) = delete; + + private: + static long volatile s_telemetryId; + + ThreadFailureCallbackHolder **m_ppThreadList; + IFailureCallback *m_pCallback; + ThreadFailureCallbackHolder *m_pNext; + DWORD m_threadId; + wil::CallContextInfo *m_pCallContext; + }; + + __declspec(selectany) long volatile ThreadFailureCallbackHolder::s_telemetryId = 1; + + template class ThreadFailureCallbackFn final : public IFailureCallback { - *callContextString = '\0'; - bool reportedTelemetry = false; - - ThreadFailureCallbackHolder** ppListeners = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal() : nullptr; - if ((ppListeners != nullptr) && (*ppListeners != nullptr)) + public: + explicit ThreadFailureCallbackFn(_In_opt_ CallContextInfo *pContext, + _Inout_ TLambda &&errorFunction) WI_NOEXCEPT + : m_errorFunction(wistd::move(errorFunction)), + m_callbackHolder(this, pContext) { - callContextString[0] = '\0'; - if (GetThreadContext(pFailure, *ppListeners, callContextString, callContextStringLength)) - { - pFailure->pszCallContext = callContextString; - } - - auto pNode = *ppListeners; - do - { - reportedTelemetry |= pNode->m_pCallback->NotifyFailure(*pFailure); - pNode = pNode->m_pNext; - } while (pNode != nullptr); } - if (g_pfnTelemetryCallback != nullptr) + ThreadFailureCallbackFn(_Inout_ ThreadFailureCallbackFn &&other) WI_NOEXCEPT + : m_errorFunction(wistd::move(other.m_errorFunction)), + m_callbackHolder(this, other.m_callbackHolder.CallContextInfo()) { - // If the telemetry was requested to be suppressed, - // pretend like it has already been reported to the fallback callback - g_pfnTelemetryCallback(reportedTelemetry || WI_IsFlagSet(pFailure->flags, FailureFlags::RequestSuppressTelemetry), *pFailure); } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override + { + return m_errorFunction(failure); + } + + private: + ThreadFailureCallbackFn(_In_ ThreadFailureCallbackFn const &); + ThreadFailureCallbackFn &operator=(_In_ ThreadFailureCallbackFn const &); + + TLambda m_errorFunction; + ThreadFailureCallbackHolder m_callbackHolder; + }; + + // returns true if telemetry was reported for this error + inline void __stdcall GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, + _Out_writes_(callContextStringLength) + _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringLength > 0) + size_t callContextStringLength) WI_NOEXCEPT + { + ThreadFailureCallbackHolder::GetContextAndNotifyFailure(pFailure, callContextString, + callContextStringLength); + + // Update the process-wide failure cache + wil::SetLastError(*pFailure); } - ThreadFailureCallbackHolder(ThreadFailureCallbackHolder const&) = delete; - ThreadFailureCallbackHolder& operator=(ThreadFailureCallbackHolder const&) = delete; + template + void InitGlobalWithStorage(WilInitializeCommand state, void *storage, T *&global, TCtorArgs &&...args) + { + if ((state == WilInitializeCommand::Create) && !global) + { + global = ::new (storage) T(wistd::forward(args)...); + } + else if ((state == WilInitializeCommand::Destroy) && global) + { + global->~T(); + global = nullptr; + } + } + } // namespace details + /// @endcond - private: - static long volatile s_telemetryId; + /** Modules that cannot use CRT-based static initialization may call this method from their entrypoint + instead. Disable the use of CRT-based initializers by defining RESULT_SUPPRESS_STATIC_INITIALIZERS + while compiling this header. Linking together libraries that disagree on this setting and calling + this method will behave correctly. It may be necessary to recompile all statically linked libraries + with the RESULT_SUPPRESS_... setting to eliminate all "LNK4201 - CRT section exists, but..." errors. + */ + inline void WilInitialize_Result(WilInitializeCommand state) + { + static unsigned char s_processLocalData[sizeof(*details_abi::g_pProcessLocalData)]; + static unsigned char s_threadFailureCallbacks[sizeof(*details::g_pThreadFailureCallbacks)]; - ThreadFailureCallbackHolder** m_ppThreadList; - IFailureCallback* m_pCallback; - ThreadFailureCallbackHolder* m_pNext; - DWORD m_threadId; - wil::CallContextInfo* m_pCallContext; - }; + details::InitGlobalWithStorage(state, s_processLocalData, details_abi::g_pProcessLocalData, "WilError_03"); + details::InitGlobalWithStorage(state, s_threadFailureCallbacks, details::g_pThreadFailureCallbacks); - __declspec(selectany) long volatile ThreadFailureCallbackHolder::s_telemetryId = 1; + if (state == WilInitializeCommand::Create) + { + details::g_pfnGetContextAndNotifyFailure = details::GetContextAndNotifyFailure; + } + } + + /// @cond + namespace details + { +#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS + __declspec(selectany) ::wil::details_abi::ProcessLocalStorage<::wil::details_abi::ProcessLocalData> + g_processLocalData("WilError_03"); + __declspec(selectany) ::wil::details_abi::ThreadLocalStorage + g_threadFailureCallbacks; + + WI_HEADER_INITIALIZATION_FUNCTION(InitializeResultHeader, [] { + g_pfnGetContextAndNotifyFailure = GetContextAndNotifyFailure; + ::wil::details_abi::g_pProcessLocalData = &g_processLocalData; + g_pThreadFailureCallbacks = &g_threadFailureCallbacks; + return 1; + }); +#endif + } // namespace details + /// @endcond + + // This helper functions much like scope_exit -- give it a lambda and get back a local object that can be used to + // catch all errors happening in your module through all WIL error handling mechanisms. The lambda will be called + // once for each error throw, error return, or error catch that is handled while the returned object is still in + // scope. Usage: + // + // auto monitor = wil::ThreadFailureCallback([](wil::FailureInfo const &failure) + // { + // // Write your code that logs or cares about failure details here... + // // It has access to HRESULT, filename, line number, etc through the failure param. + // }); + // + // As long as the returned 'monitor' object remains in scope, the lambda will continue to receive callbacks for any + // failures that occur in this module on the calling thread. Note that this will guarantee that the lambda will run + // for any failure that is through any of the WIL macros (THROW_XXX, RETURN_XXX, LOG_XXX, etc). template - class ThreadFailureCallbackFn final : public IFailureCallback + inline wil::details::ThreadFailureCallbackFn ThreadFailureCallback(_Inout_ TLambda &&fnAtExit) WI_NOEXCEPT { - public: - explicit ThreadFailureCallbackFn(_In_opt_ CallContextInfo* pContext, _Inout_ TLambda&& errorFunction) WI_NOEXCEPT - : m_errorFunction(wistd::move(errorFunction)), - m_callbackHolder(this, pContext) + return wil::details::ThreadFailureCallbackFn(nullptr, wistd::forward(fnAtExit)); + } + + // Much like ThreadFailureCallback, this class will receive WIL failure notifications from the time it's + // instantiated until the time that it's destroyed. At any point during that time you can ask for the last failure + // that was seen by any of the WIL macros (RETURN_XXX, THROW_XXX, LOG_XXX, etc) on the current thread. + // + // This class is most useful when utilized as a member of an RAII class that's dedicated to providing logging or + // telemetry. In the destructor of that class, if the operation had not been completed successfully (it goes out of + // scope due to early return or exception unwind before success is acknowledged) then details about the last failure + // can be retrieved and appropriately logged. + // + // Usage: + // + // class MyLogger + // { + // public: + // MyLogger() : m_fComplete(false) {} + // ~MyLogger() + // { + // if (!m_fComplete) + // { + // FailureInfo *pFailure = m_cache.GetFailure(); + // if (pFailure != nullptr) + // { + // // Log information about pFailure (pFileure->hr, pFailure->pszFile, pFailure->uLineNumber, etc) + // } + // else + // { + // // It's possible that you get stack unwind from an exception that did NOT come through WIL + // // like (std::bad_alloc from the STL). Use a reasonable default like: + // HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION). + // } + // } + // } + // void Complete() { m_fComplete = true; } + // private: + // bool m_fComplete; + // ThreadFailureCache m_cache; + // }; + + class ThreadFailureCache final : public details::IFailureCallback + { + public: + ThreadFailureCache() : m_callbackHolder(this) { } - ThreadFailureCallbackFn(_Inout_ ThreadFailureCallbackFn&& other) WI_NOEXCEPT - : m_errorFunction(wistd::move(other.m_errorFunction)), - m_callbackHolder(this, other.m_callbackHolder.CallContextInfo()) + ThreadFailureCache(ThreadFailureCache &&rhs) WI_NOEXCEPT : m_failure(wistd::move(rhs.m_failure)), + m_callbackHolder(this) { } - bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT override + ThreadFailureCache &operator=(ThreadFailureCache &&rhs) WI_NOEXCEPT { - return m_errorFunction(failure); + m_failure = wistd::move(rhs.m_failure); + return *this; } - private: - ThreadFailureCallbackFn(_In_ ThreadFailureCallbackFn const&); - ThreadFailureCallbackFn& operator=(_In_ ThreadFailureCallbackFn const&); + void WatchCurrentThread() + { + m_callbackHolder.StartWatching(); + } - TLambda m_errorFunction; - ThreadFailureCallbackHolder m_callbackHolder; + void IgnoreCurrentThread() + { + m_callbackHolder.StopWatching(); + } + + FailureInfo const *GetFailure() + { + return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr); + } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override + { + // When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT + // generated, so we ignore subsequent failures on the same error code (assuming propagation). + + if (failure.hr != m_failure.GetFailureInfo().hr) + { + m_failure.SetFailureInfo(failure); + } + return false; + } + + private: + StoredFailureInfo m_failure; + details::ThreadFailureCallbackHolder m_callbackHolder; }; - // returns true if telemetry was reported for this error - inline void __stdcall GetContextAndNotifyFailure( - _Inout_ FailureInfo* pFailure, - _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT - { - ThreadFailureCallbackHolder::GetContextAndNotifyFailure(pFailure, callContextString, callContextStringLength); - - // Update the process-wide failure cache - wil::SetLastError(*pFailure); - } - - template - void InitGlobalWithStorage(WilInitializeCommand state, void* storage, T*& global, TCtorArgs&&... args) - { - if ((state == WilInitializeCommand::Create) && !global) - { - global = ::new (storage) T(wistd::forward(args)...); - } - else if ((state == WilInitializeCommand::Destroy) && global) - { - global->~T(); - global = nullptr; - } - } -} // namespace details -/// @endcond - -/** Modules that cannot use CRT-based static initialization may call this method from their entrypoint - instead. Disable the use of CRT-based initializers by defining RESULT_SUPPRESS_STATIC_INITIALIZERS - while compiling this header. Linking together libraries that disagree on this setting and calling - this method will behave correctly. It may be necessary to recompile all statically linked libraries - with the RESULT_SUPPRESS_... setting to eliminate all "LNK4201 - CRT section exists, but..." errors. -*/ -inline void WilInitialize_Result(WilInitializeCommand state) -{ - static unsigned char s_processLocalData[sizeof(*details_abi::g_pProcessLocalData)]; - static unsigned char s_threadFailureCallbacks[sizeof(*details::g_pThreadFailureCallbacks)]; - - details::InitGlobalWithStorage(state, s_processLocalData, details_abi::g_pProcessLocalData, "WilError_03"); - details::InitGlobalWithStorage(state, s_threadFailureCallbacks, details::g_pThreadFailureCallbacks); - - if (state == WilInitializeCommand::Create) - { - details::g_pfnGetContextAndNotifyFailure = details::GetContextAndNotifyFailure; - } -} - -/// @cond -namespace details -{ -#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS - __declspec(selectany) ::wil::details_abi::ProcessLocalStorage<::wil::details_abi::ProcessLocalData> g_processLocalData("WilError_03"); - __declspec(selectany) ::wil::details_abi::ThreadLocalStorage g_threadFailureCallbacks; - - WI_HEADER_INITIALIZATION_FUNCTION(InitializeResultHeader, [] { - g_pfnGetContextAndNotifyFailure = GetContextAndNotifyFailure; - ::wil::details_abi::g_pProcessLocalData = &g_processLocalData; - g_pThreadFailureCallbacks = &g_threadFailureCallbacks; - return 1; - }); -#endif -} // namespace details -/// @endcond - -// This helper functions much like scope_exit -- give it a lambda and get back a local object that can be used to -// catch all errors happening in your module through all WIL error handling mechanisms. The lambda will be called -// once for each error throw, error return, or error catch that is handled while the returned object is still in -// scope. Usage: -// -// auto monitor = wil::ThreadFailureCallback([](wil::FailureInfo const &failure) -// { -// // Write your code that logs or cares about failure details here... -// // It has access to HRESULT, filename, line number, etc through the failure param. -// }); -// -// As long as the returned 'monitor' object remains in scope, the lambda will continue to receive callbacks for any -// failures that occur in this module on the calling thread. Note that this will guarantee that the lambda will run -// for any failure that is through any of the WIL macros (THROW_XXX, RETURN_XXX, LOG_XXX, etc). - -template -inline wil::details::ThreadFailureCallbackFn ThreadFailureCallback(_Inout_ TLambda&& fnAtExit) WI_NOEXCEPT -{ - return wil::details::ThreadFailureCallbackFn(nullptr, wistd::forward(fnAtExit)); -} - -// Much like ThreadFailureCallback, this class will receive WIL failure notifications from the time it's instantiated -// until the time that it's destroyed. At any point during that time you can ask for the last failure that was seen -// by any of the WIL macros (RETURN_XXX, THROW_XXX, LOG_XXX, etc) on the current thread. -// -// This class is most useful when utilized as a member of an RAII class that's dedicated to providing logging or -// telemetry. In the destructor of that class, if the operation had not been completed successfully (it goes out of -// scope due to early return or exception unwind before success is acknowledged) then details about the last failure -// can be retrieved and appropriately logged. -// -// Usage: -// -// class MyLogger -// { -// public: -// MyLogger() : m_fComplete(false) {} -// ~MyLogger() -// { -// if (!m_fComplete) -// { -// FailureInfo *pFailure = m_cache.GetFailure(); -// if (pFailure != nullptr) -// { -// // Log information about pFailure (pFileure->hr, pFailure->pszFile, pFailure->uLineNumber, etc) -// } -// else -// { -// // It's possible that you get stack unwind from an exception that did NOT come through WIL -// // like (std::bad_alloc from the STL). Use a reasonable default like: HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION). -// } -// } -// } -// void Complete() { m_fComplete = true; } -// private: -// bool m_fComplete; -// ThreadFailureCache m_cache; -// }; - -class ThreadFailureCache final : public details::IFailureCallback -{ -public: - ThreadFailureCache() : m_callbackHolder(this) - { - } - - ThreadFailureCache(ThreadFailureCache&& rhs) WI_NOEXCEPT : m_failure(wistd::move(rhs.m_failure)), m_callbackHolder(this) - { - } - - ThreadFailureCache& operator=(ThreadFailureCache&& rhs) WI_NOEXCEPT - { - m_failure = wistd::move(rhs.m_failure); - return *this; - } - - void WatchCurrentThread() - { - m_callbackHolder.StartWatching(); - } - - void IgnoreCurrentThread() - { - m_callbackHolder.StopWatching(); - } - - FailureInfo const* GetFailure() - { - return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr); - } - - bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT override - { - // When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT - // generated, so we ignore subsequent failures on the same error code (assuming propagation). - - if (failure.hr != m_failure.GetFailureInfo().hr) - { - m_failure.SetFailureInfo(failure); - } - return false; - } - -private: - StoredFailureInfo m_failure; - details::ThreadFailureCallbackHolder m_callbackHolder; -}; - } // namespace wil #pragma warning(pop) diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_macros.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_macros.h index 1848a7c..516cb36 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_macros.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_macros.h @@ -9,8 +9,8 @@ // //********************************************************* //! @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. +//! 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. #ifndef __WIL_RESULTMACROS_INCLUDED #define __WIL_RESULTMACROS_INCLUDED @@ -27,7 +27,8 @@ // for driver projects. We mimic the behavior of NT_ASSERT which checks only for DBG. // RESULT_NO_DEBUG is provided as an opt-out mechanism. #ifndef RESULT_DEBUG -#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(RESULT_NO_DEBUG) && (defined(WIL_KERNEL_MODE) || !defined(NDEBUG)) +#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(RESULT_NO_DEBUG) && \ + (defined(WIL_KERNEL_MODE) || !defined(NDEBUG)) #define RESULT_DEBUG #endif #endif @@ -63,9 +64,11 @@ #endif #define WI_ASSERT_FAIL(msg) __WI_ASSERT_FAIL_ANNOTATION(L"" msg), DbgRaiseAssertionFailure() -#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (WI_ASSERT_FAIL(#condition), FALSE) : TRUE)) -#define WI_ASSERT_MSG(condition, msg) \ - (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE)) +#define WI_ASSERT(condition) \ + (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (WI_ASSERT_FAIL(#condition), FALSE) : TRUE)) +#define WI_ASSERT_MSG(condition, msg) \ + (__WI_ANALYSIS_ASSUME(condition), \ + ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE)) #define WI_ASSERT_NOASSUME WI_ASSERT #define WI_ASSERT_MSG_NOASSUME WI_ASSERT_MSG #define WI_VERIFY WI_ASSERT @@ -79,7 +82,8 @@ #define WI_ASSERT_MSG_NOASSUME(condition, msg) ((void)0) #define WI_VERIFY(condition) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) #define WI_VERIFY_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) -#define WI_VERIFY_SUCCEEDED(condition) (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE)) +#define WI_VERIFY_SUCCEEDED(condition) \ + (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE)) #endif // RESULT_DEBUG #if !defined(_NTDEF_) @@ -92,8 +96,9 @@ typedef _Return_type_success_(return >= 0) LONG NTSTATUS; #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #endif #ifndef __NTSTATUS_FROM_WIN32 -#define __NTSTATUS_FROM_WIN32(x) \ - ((NTSTATUS)(x) <= 0 ? ((NTSTATUS)(x)) : ((NTSTATUS)(((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | ERROR_SEVERITY_ERROR))) +#define __NTSTATUS_FROM_WIN32(x) \ + ((NTSTATUS)(x) <= 0 ? ((NTSTATUS)(x)) \ + : ((NTSTATUS)(((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | ERROR_SEVERITY_ERROR))) #endif #ifndef WIL_AllocateMemory @@ -132,9 +137,9 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #if defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -#include #include // provides the _ReturnAddress() intrinsic #include // provides 'operator new', 'std::nothrow', etc. +#include #if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW) #include // provides std::bad_alloc in the windows and public CRT headers #endif @@ -249,18 +254,18 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") /// @cond #define __R_DIAGNOSTICS(diagnostics) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr -#define __R_DIAGNOSTICS_RA(diagnostics, address) \ +#define __R_DIAGNOSTICS_RA(diagnostics, address) \ diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr, address -#define __R_FN_PARAMS_FULL \ +#define __R_FN_PARAMS_FULL \ _In_opt_ void *callerReturnAddress, unsigned int lineNumber, _In_opt_ PCSTR fileName, _In_opt_ PCSTR functionName, \ _In_opt_ PCSTR code, void *returnAddress -#define __R_FN_LOCALS_FULL_RA \ - void* callerReturnAddress = nullptr; \ - unsigned int lineNumber = 0; \ - PCSTR fileName = nullptr; \ - PCSTR functionName = nullptr; \ - PCSTR code = nullptr; \ - void* returnAddress = _ReturnAddress(); +#define __R_FN_LOCALS_FULL_RA \ + void *callerReturnAddress = nullptr; \ + unsigned int lineNumber = 0; \ + PCSTR fileName = nullptr; \ + PCSTR functionName = nullptr; \ + PCSTR code = nullptr; \ + void *returnAddress = _ReturnAddress(); // NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases // This entire section will be repeated below for fail fast (__RFF_ prefix). #define __R_COMMA , @@ -316,50 +321,51 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __R_IF_TRAIL_COMMA #endif // Assemble the varying amounts of data into a single macro -#define __R_INFO_ONLY(CODE) \ - __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \ - __R_IF_LINE(__R_LINE_VALUE) \ +#define __R_INFO_ONLY(CODE) \ + __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \ + __R_IF_LINE(__R_LINE_VALUE) \ __R_IF_FILE(__R_COMMA __R_FILE_VALUE) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) #define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA -#define __R_INFO_NOFILE_ONLY(CODE) \ - __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \ - __R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) +#define __R_INFO_NOFILE_ONLY(CODE) \ + __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \ + __R_IF_LINE(__R_LINE_VALUE) \ + __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) #define __R_INFO_NOFILE(CODE) __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA -#define __R_FN_PARAMS_ONLY \ - __R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) \ - __R_IF_LINE(unsigned int lineNumber) \ - __R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) \ +#define __R_FN_PARAMS_ONLY \ + __R_IF_CALLERADDRESS(void *callerReturnAddress __R_IF_COMMA) \ + __R_IF_LINE(unsigned int lineNumber) \ + __R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) \ __R_IF_FUNCTION(__R_COMMA _In_opt_ PCSTR functionName) __R_IF_CODE(__R_COMMA _In_opt_ PCSTR code) #define __R_FN_PARAMS __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA -#define __R_FN_CALL_ONLY \ - __R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) \ - __R_IF_LINE(lineNumber) __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code) +#define __R_FN_CALL_ONLY \ + __R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) \ + __R_IF_LINE(lineNumber) \ + __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code) #define __R_FN_CALL __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA -#define __R_FN_LOCALS \ - __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \ - __R_IF_NOT_LINE(unsigned int lineNumber = 0;) \ - __R_IF_NOT_FILE(PCSTR fileName = nullptr;) \ +#define __R_FN_LOCALS \ + __R_IF_NOT_CALLERADDRESS(void *callerReturnAddress = nullptr;) \ + __R_IF_NOT_LINE(unsigned int lineNumber = 0;) \ + __R_IF_NOT_FILE(PCSTR fileName = nullptr;) \ __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) -#define __R_FN_LOCALS_RA \ - __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \ - __R_IF_NOT_LINE(unsigned int lineNumber = 0;) \ - __R_IF_NOT_FILE(PCSTR fileName = nullptr;) \ - __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) \ - __R_IF_NOT_CODE(PCSTR code = nullptr;) void* returnAddress = _ReturnAddress(); -#define __R_FN_UNREFERENCED \ - __R_IF_CALLERADDRESS((void)callerReturnAddress;) \ - __R_IF_LINE((void)lineNumber;) __R_IF_FILE((void)fileName;) __R_IF_FUNCTION((void)functionName;) __R_IF_CODE((void)code;) +#define __R_FN_LOCALS_RA \ + __R_IF_NOT_CALLERADDRESS(void *callerReturnAddress = nullptr;) \ + __R_IF_NOT_LINE(unsigned int lineNumber = 0;) \ + __R_IF_NOT_FILE(PCSTR fileName = nullptr;) \ + __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) \ + __R_IF_NOT_CODE(PCSTR code = nullptr;) void *returnAddress = _ReturnAddress(); +#define __R_FN_UNREFERENCED \ + __R_IF_CALLERADDRESS((void)callerReturnAddress;) \ + __R_IF_LINE((void)lineNumber;) \ + __R_IF_FILE((void)fileName;) __R_IF_FUNCTION((void)functionName;) __R_IF_CODE((void)code;) // 1) Direct Methods // * Called Directly by Macros // * Always noinline // * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) #if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_DIRECT_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RetType MethodName -#define __R_DIRECT_NORET_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#define __R_DIRECT_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RetType MethodName +#define __R_DIRECT_NORET_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RESULT_NORETURN RetType MethodName #else #define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName #define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName @@ -370,17 +376,17 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __R_DIRECT_FN_CALL_ONLY __R_FN_CALL_FULL_RA // 2) Internal Methods // * Only called by Conditional routines -// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1) +// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly +// called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and +// RESULT_INLINE_ERROR_TESTS = 1) #if (RESULT_DIAGNOSTICS_LEVEL == 1) #define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName #define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __R_INTERNAL_INLINE_METHOD(MethodName) \ - template \ - inline __declspec(noinline) void MethodName -#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) \ - template \ - inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_INTERNAL_INLINE_METHOD(MethodName) \ + template inline __declspec(noinline) void MethodName +#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) \ + template inline __declspec(noinline) RESULT_NORETURN void MethodName #define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName #else #define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName @@ -390,8 +396,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName #endif #define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName -#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void* returnAddress __R_COMMA -#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void* returnAddress +#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void *returnAddress __R_COMMA +#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void *returnAddress #define __R_INTERNAL_NOINLINE_FN_CALL __R_FN_CALL_FULL __R_COMMA #define __R_INTERNAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL_FULL #define __R_INTERNAL_INLINE_FN_PARAMS __R_FN_PARAMS @@ -420,13 +426,11 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS) // * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) #if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RetType MethodName #define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \ - template \ - __forceinline RetType MethodName +#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \ + template __forceinline RetType MethodName #define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName #define __R_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __R_COMMA #else @@ -454,7 +458,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __R_CONDITIONAL_FN_PARAMS __R_FN_PARAMS #define __R_CONDITIONAL_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY // Macro call-site helpers -#define __R_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __R_NS_ASSEMBLE2(ri, rd) \ + in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes #define __R_NS_ASSEMBLE(ri, rd) __R_NS_ASSEMBLE2(ri, rd) #define __R_NS_NAME __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL) #define __R_NS wil::details::__R_NS_NAME @@ -465,8 +470,9 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #endif // NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases // This entire section is repeated below for fail fast (__RFF_ prefix). For ease of editing this section, the -// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST), -// (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST) +// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> +// RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST), (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and +// (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST) #define __RFF_COMMA , #define __RFF_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress #define __RFF_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() @@ -514,46 +520,45 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __RFF_IF_TRAIL_COMMA #endif // Assemble the varying amounts of data into a single macro -#define __RFF_INFO_ONLY(CODE) \ - __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \ - __RFF_IF_LINE(__R_LINE_VALUE) \ - __RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) +#define __RFF_INFO_ONLY(CODE) \ + __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \ + __RFF_IF_LINE(__R_LINE_VALUE) \ + __RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) \ + __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) #define __RFF_INFO(CODE) __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA -#define __RFF_INFO_NOFILE_ONLY(CODE) \ - __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \ - __RFF_IF_LINE(__R_LINE_VALUE) \ +#define __RFF_INFO_NOFILE_ONLY(CODE) \ + __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \ + __RFF_IF_LINE(__R_LINE_VALUE) \ __RFF_IF_FILE(__RFF_COMMA "wil") __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) #define __RFF_INFO_NOFILE(CODE) __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA -#define __RFF_FN_PARAMS_ONLY \ - __RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) \ - __RFF_IF_LINE(unsigned int lineNumber) \ - __RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) \ +#define __RFF_FN_PARAMS_ONLY \ + __RFF_IF_CALLERADDRESS(void *callerReturnAddress __RFF_IF_COMMA) \ + __RFF_IF_LINE(unsigned int lineNumber) \ + __RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) \ __RFF_IF_FUNCTION(__RFF_COMMA _In_opt_ PCSTR functionName) __RFF_IF_CODE(__RFF_COMMA _In_opt_ PCSTR code) #define __RFF_FN_PARAMS __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA -#define __RFF_FN_CALL_ONLY \ - __RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) \ - __RFF_IF_LINE(lineNumber) \ +#define __RFF_FN_CALL_ONLY \ + __RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) \ + __RFF_IF_LINE(lineNumber) \ __RFF_IF_FILE(__RFF_COMMA fileName) __RFF_IF_FUNCTION(__RFF_COMMA functionName) __RFF_IF_CODE(__RFF_COMMA code) #define __RFF_FN_CALL __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA -#define __RFF_FN_LOCALS \ - __RFF_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \ - __RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) \ - __RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) \ +#define __RFF_FN_LOCALS \ + __RFF_IF_NOT_CALLERADDRESS(void *callerReturnAddress = nullptr;) \ + __RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) \ + __RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) \ __RFF_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __RFF_IF_NOT_CODE(PCSTR code = nullptr;) -#define __RFF_FN_UNREFERENCED \ - __RFF_IF_CALLERADDRESS(callerReturnAddress;) \ +#define __RFF_FN_UNREFERENCED \ + __RFF_IF_CALLERADDRESS(callerReturnAddress;) \ __RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;) // 1) Direct Methods // * Called Directly by Macros // * Always noinline // * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_DIRECT_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RetType MethodName -#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#define __RFF_DIRECT_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RetType MethodName +#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RESULT_NORETURN RetType MethodName #else #define __RFF_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName #define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName @@ -564,17 +569,17 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __RFF_DIRECT_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA // 2) Internal Methods // * Only called by Conditional routines -// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise noinline (directly called by code when branching is forceinlined) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1) +// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise +// noinline (directly called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and +// RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1) #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) #define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName #define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __RFF_INTERNAL_INLINE_METHOD(MethodName) \ - template \ - inline __declspec(noinline) void MethodName -#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) \ - template \ - inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_INTERNAL_INLINE_METHOD(MethodName) \ + template inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) \ + template inline __declspec(noinline) RESULT_NORETURN void MethodName #define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName #else #define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName @@ -584,8 +589,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName #endif #define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName -#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void* returnAddress __RFF_COMMA -#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void* returnAddress +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void *returnAddress __RFF_COMMA +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void *returnAddress #define __RFF_INTERNAL_NOINLINE_FN_CALL __RFF_FN_CALL_FULL __RFF_COMMA #define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL #define __RFF_INTERNAL_INLINE_FN_PARAMS __RFF_FN_PARAMS @@ -614,13 +619,11 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST) // * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \ - template \ - inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \ + template inline __declspec(noinline) RetType MethodName #define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \ - template \ - __forceinline RetType MethodName +#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \ + template __forceinline RetType MethodName #define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName #define __RFF_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __RFF_COMMA #else @@ -648,7 +651,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __RFF_CONDITIONAL_FN_PARAMS __RFF_FN_PARAMS #define __RFF_CONDITIONAL_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY // Macro call-site helpers -#define __RFF_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __RFF_NS_ASSEMBLE2(ri, rd) \ + in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes #define __RFF_NS_ASSEMBLE(ri, rd) __RFF_NS_ASSEMBLE2(ri, rd) #define __RFF_NS_NAME __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST) #define __RFF_NS wil::details::__RFF_NS_NAME @@ -670,146 +674,146 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #endif // Helpers for return macros -#define __RETURN_HR_MSG(hr, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - if (FAILED(__hr)) \ - { \ - __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - } \ - return __hr; \ - } \ +#define __RETURN_HR_MSG(hr, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + if (FAILED(__hr)) \ + { \ + __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + } \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - return __hr; \ - } \ +#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_WIN32_MSG(err, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __err = (err); \ - if (FAILED_WIN32(__err)) \ - { \ - return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - } \ - return S_OK; \ - } \ +#define __RETURN_WIN32_MSG(err, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __err = (err); \ + if (FAILED_WIN32(__err)) \ + { \ + return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + } \ + return S_OK; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __err = (err); \ - return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - } \ +#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __err = (err); \ + return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) \ +#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) \ return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __status = (status); \ - if (FAILED_NTSTATUS(__status)) \ - { \ - return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - } \ - return S_OK; \ - } \ +#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __status = (status); \ + if (FAILED_NTSTATUS(__status)) \ + { \ + return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + } \ + return S_OK; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __status = (status); \ - return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ - } \ +#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __status = (status); \ + return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR(hr, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - if (FAILED(__hr)) \ - { \ - __R_FN(Return_Hr)(__R_INFO(str) __hr); \ - } \ - return __hr; \ - } \ +#define __RETURN_HR(hr, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + if (FAILED(__hr)) \ + { \ + __R_FN(Return_Hr)(__R_INFO(str) __hr); \ + } \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR_NOFILE(hr, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - if (FAILED(__hr)) \ - { \ - __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \ - } \ - return __hr; \ - } \ +#define __RETURN_HR_NOFILE(hr, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + if (FAILED(__hr)) \ + { \ + __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \ + } \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR_FAIL(hr, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - __R_FN(Return_Hr)(__R_INFO(str) __hr); \ - return __hr; \ - } \ +#define __RETURN_HR_FAIL(hr, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + __R_FN(Return_Hr)(__R_INFO(str) __hr); \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR_FAIL_SUPPRESS_TELEMETRY(hr, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - __R_FN(Return_HrSuppressTelemetry)(__R_INFO(str) __hr); \ - return __hr; \ - } \ +#define __RETURN_HR_FAIL_SUPPRESS_TELEMETRY(hr, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + __R_FN(Return_HrSuppressTelemetry)(__R_INFO(str) __hr); \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_HR_FAIL_NOFILE(hr, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const HRESULT __hr = (hr); \ - __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \ - return __hr; \ - } \ +#define __RETURN_HR_FAIL_NOFILE(hr, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const HRESULT __hr = (hr); \ + __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \ + return __hr; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_WIN32(err, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __err = (err); \ - if (FAILED_WIN32(__err)) \ - { \ - return __R_FN(Return_Win32)(__R_INFO(str) __err); \ - } \ - return S_OK; \ - } \ +#define __RETURN_WIN32(err, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __err = (err); \ + if (FAILED_WIN32(__err)) \ + { \ + return __R_FN(Return_Win32)(__R_INFO(str) __err); \ + } \ + return S_OK; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_WIN32_FAIL(err, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __err = (err); \ - return __R_FN(Return_Win32)(__R_INFO(str) __err); \ - } \ +#define __RETURN_WIN32_FAIL(err, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __err = (err); \ + return __R_FN(Return_Win32)(__R_INFO(str) __err); \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) #define __RETURN_GLE_FAIL(str) return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str)) #define __RETURN_GLE_FAIL_NOFILE(str) return __R_FN(Return_GetLastError)(__R_INFO_NOFILE_ONLY(str)) -#define __RETURN_NTSTATUS(status, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __status = (status); \ - if (FAILED_NTSTATUS(__status)) \ - { \ - return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \ - } \ - return S_OK; \ - } \ +#define __RETURN_NTSTATUS(status, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __status = (status); \ + if (FAILED_NTSTATUS(__status)) \ + { \ + return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \ + } \ + return S_OK; \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define __RETURN_NTSTATUS_FAIL(status, str) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __status = (status); \ - return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \ - } \ +#define __RETURN_NTSTATUS_FAIL(status, str) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __status = (status); \ + return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) /// @endcond @@ -824,90 +828,90 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define RETURN_NTSTATUS(status) __RETURN_NTSTATUS(status, #status) // Conditionally returns failures (HRESULT) - always logs failures -#define RETURN_IF_FAILED(hr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - __RETURN_HR_FAIL(__hrRet, #hr); \ - } \ - } \ +#define RETURN_IF_FAILED(hr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + __RETURN_HR_FAIL(__hrRet, #hr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const auto __boolRet = wil::verify_BOOL(win32BOOL); \ - if (!__boolRet) \ - { \ - __RETURN_GLE_FAIL(#win32BOOL); \ - } \ - } \ +#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const auto __boolRet = wil::verify_BOOL(win32BOOL); \ + if (!__boolRet) \ + { \ + __RETURN_GLE_FAIL(#win32BOOL); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_ERROR(win32err) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __errRet = (win32err); \ - if (FAILED_WIN32(__errRet)) \ - { \ - __RETURN_WIN32_FAIL(__errRet, #win32err); \ - } \ - } \ +#define RETURN_IF_WIN32_ERROR(win32err) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __errRet = (win32err); \ + if (FAILED_WIN32(__errRet)) \ + { \ + __RETURN_WIN32_FAIL(__errRet, #win32err); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NULL_ALLOC(ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); \ - } \ - } \ +#define RETURN_IF_NULL_ALLOC(ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF(hr, condition) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - __RETURN_HR(wil::verify_hresult(hr), #condition); \ - } \ - } \ +#define RETURN_HR_IF(hr, condition) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + __RETURN_HR(wil::verify_hresult(hr), #condition); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF_NULL(hr, ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_HR(wil::verify_hresult(hr), #ptr); \ - } \ - } \ +#define RETURN_HR_IF_NULL(hr, ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_HR(wil::verify_hresult(hr), #ptr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF(condition) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - __RETURN_GLE_FAIL(#condition); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF(condition) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + __RETURN_GLE_FAIL(#condition); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL(ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_GLE_FAIL(#ptr); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF_NULL(ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_GLE_FAIL(#ptr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED(status) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __statusRet = (status); \ - if (FAILED_NTSTATUS(__statusRet)) \ - { \ - __RETURN_NTSTATUS_FAIL(__statusRet, #status); \ - } \ - } \ +#define RETURN_IF_NTSTATUS_FAILED(status) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __statusRet = (status); \ + if (FAILED_NTSTATUS(__statusRet)) \ + { \ + __RETURN_NTSTATUS_FAIL(__statusRet, #status); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) // Always returns a known failure (HRESULT) - always logs a var-arg message on failure @@ -917,207 +921,208 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define RETURN_NTSTATUS_MSG(status, fmt, ...) __RETURN_NTSTATUS_MSG(status, #status, fmt, ##__VA_ARGS__) // Conditionally returns failures (HRESULT) - always logs a var-arg message on failure -#define RETURN_IF_FAILED_MSG(hr, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - __RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_IF_FAILED_MSG(hr, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + __RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (!wil::verify_BOOL(win32BOOL)) \ - { \ - __RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (!wil::verify_BOOL(win32BOOL)) \ + { \ + __RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __errRet = (win32err); \ - if (FAILED_WIN32(__errRet)) \ - { \ - __RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __errRet = (win32err); \ + if (FAILED_WIN32(__errRet)) \ + { \ + __RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - __RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + __RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - __RETURN_GLE_MSG_FAIL(#condition, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + __RETURN_GLE_MSG_FAIL(#condition, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_GLE_MSG_FAIL(#ptr, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_GLE_MSG_FAIL(#ptr, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __statusRet = (status); \ - if (FAILED_NTSTATUS(__statusRet)) \ - { \ - __RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, ##__VA_ARGS__); \ - } \ - } \ +#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __statusRet = (status); \ + if (FAILED_NTSTATUS(__statusRet)) \ + { \ + __RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, ##__VA_ARGS__); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern -#define RETURN_IF_FAILED_EXPECTED(hr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - return __hrRet; \ - } \ - } \ +// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged +// - macros are only for control flow pattern +#define RETURN_IF_FAILED_EXPECTED(hr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + return __hrRet; \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (!wil::verify_BOOL(win32BOOL)) \ - { \ - return wil::details::GetLastErrorFailHr(); \ - } \ - } \ +#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (!wil::verify_BOOL(win32BOOL)) \ + { \ + return wil::details::GetLastErrorFailHr(); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const DWORD __errRet = (win32err); \ - if (FAILED_WIN32(__errRet)) \ - { \ - return __HRESULT_FROM_WIN32(__errRet); \ - } \ - } \ +#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const DWORD __errRet = (win32err); \ + if (FAILED_WIN32(__errRet)) \ + { \ + return __HRESULT_FROM_WIN32(__errRet); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - return E_OUTOFMEMORY; \ - } \ - } \ +#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + return E_OUTOFMEMORY; \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF_EXPECTED(hr, condition) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - return wil::verify_hresult(hr); \ - } \ - } \ +#define RETURN_HR_IF_EXPECTED(hr, condition) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + return wil::verify_hresult(hr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - return wil::verify_hresult(hr); \ - } \ - } \ +#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + return wil::verify_hresult(hr); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_EXPECTED(condition) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if (wil::verify_bool(condition)) \ - { \ - return wil::details::GetLastErrorFailHr(); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF_EXPECTED(condition) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if (wil::verify_bool(condition)) \ + { \ + return wil::details::GetLastErrorFailHr(); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - if ((ptr) == nullptr) \ - { \ - return wil::details::GetLastErrorFailHr(); \ - } \ - } \ +#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + if ((ptr) == nullptr) \ + { \ + return wil::details::GetLastErrorFailHr(); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) \ - __WI_SUPPRESS_BREAKING_WARNINGS_S do \ - { \ - const NTSTATUS __statusRet = (status); \ - if (FAILED_NTSTATUS(__statusRet)) \ - { \ - return wil::details::NtStatusToHr(__statusRet); \ - } \ - } \ +#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) \ + __WI_SUPPRESS_BREAKING_WARNINGS_S do \ + { \ + const NTSTATUS __statusRet = (status); \ + if (FAILED_NTSTATUS(__statusRet)) \ + { \ + return wil::details::NtStatusToHr(__statusRet); \ + } \ + } \ __WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0) /// @cond #define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e)) /// @endcond -#define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ - do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ - { \ - return __hrRet; \ - } \ - __RETURN_HR_FAIL(__hrRet, #hr); \ - } \ +#define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ + do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ + { \ + return __hrRet; \ + } \ + __RETURN_HR_FAIL(__hrRet, #hr); \ + } \ } while ((void)0, 0) // Always logs failed HR, if expected, telemetry will be called with 'alreadyReported' -#define RETURN_IF_FAILED_SUPPRESS_TELEMETRY_IF_EXPECTED(hr, hrExpected, ...) \ - do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ - { \ - __RETURN_HR_FAIL_SUPPRESS_TELEMETRY(__hrRet, #hr); \ - } \ - __RETURN_HR_FAIL(__hrRet, #hr); \ - } \ +#define RETURN_IF_FAILED_SUPPRESS_TELEMETRY_IF_EXPECTED(hr, hrExpected, ...) \ + do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ + { \ + __RETURN_HR_FAIL_SUPPRESS_TELEMETRY(__hrRet, #hr); \ + } \ + __RETURN_HR_FAIL(__hrRet, #hr); \ + } \ } while ((void)0, 0) //***************************************************************************** @@ -1132,10 +1137,12 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // Conditionally logs failures - returns parameter value #define LOG_IF_FAILED(hr) __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) \ + __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) #define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err) #define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr) -#define LOG_HR_IF(hr, condition) __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define LOG_HR_IF(hr, condition) \ + __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) #define LOG_HR_IF_NULL(hr, ptr) __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) #define LOG_LAST_ERROR_IF(condition) __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) #define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) @@ -1153,41 +1160,44 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define NT_SUCCESS_LOG(status) NT_SUCCESS(LOG_IF_NTSTATUS_FAILED(status)) // Always logs a known failure - logs a var-arg message on failure -#define LOG_HR_MSG(hr, fmt, ...) __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_MSG(fmt, ...) __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_WIN32_MSG(win32err, fmt, ...) \ +#define LOG_HR_MSG(hr, fmt, ...) \ + __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define LOG_LAST_ERROR_MSG(fmt, ...) \ + __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define LOG_WIN32_MSG(win32err, fmt, ...) \ __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_NTSTATUS_MSG(status, fmt, ...) \ +#define LOG_NTSTATUS_MSG(status, fmt, ...) \ __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Conditionally logs failures - returns parameter value - logs a var-arg message on failure -#define LOG_IF_FAILED_MSG(hr, fmt, ...) \ +#define LOG_IF_FAILED_MSG(hr, fmt, ...) \ __R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ - __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ +#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ + __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ +#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_HR_IF_MSG(hr, condition, fmt, ...) \ - __R_FN(Log_HrIfMsg) \ +#define LOG_HR_IF_MSG(hr, condition, fmt, ...) \ + __R_FN(Log_HrIfMsg) \ (__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ +#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) \ - __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ +#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) \ + __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ +#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) /// @cond #define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e) /// @endcond -#define LOG_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ - __R_FN(Log_IfFailedWithExpected) \ - (__R_INFO(#hr) wil::verify_hresult(hr), \ - WI_ARGS_COUNT(__VA_ARGS__) + 1, \ +#define LOG_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ + __R_FN(Log_IfFailedWithExpected) \ + (__R_INFO(#hr) wil::verify_hresult(hr), WI_ARGS_COUNT(__VA_ARGS__) + 1, \ wil::verify_hresult(hrExpected) WI_FOREACH(__WI_COMMA_EXPECTED_HRESULT, ##__VA_ARGS__)) //***************************************************************************** @@ -1202,48 +1212,51 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // Conditionally fail fast failures - returns parameter value #define FAIL_FAST_IF_FAILED(hr) __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr)) -#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) \ +#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) \ __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) #define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err) #define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr) -#define FAIL_FAST_HR_IF(hr, condition) \ +#define FAIL_FAST_HR_IF(hr, condition) \ __RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) #define FAIL_FAST_HR_IF_NULL(hr, ptr) __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr) -#define FAIL_FAST_LAST_ERROR_IF(condition) __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_LAST_ERROR_IF(condition) \ + __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition)) #define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr) #define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status) // Always fail fast a known failure - fail fast a var-arg message on failure -#define FAIL_FAST_HR_MSG(hr, fmt, ...) \ +#define FAIL_FAST_HR_MSG(hr, fmt, ...) \ __RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) \ +#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) \ __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) \ +#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) \ __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) \ +#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) \ __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure -#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) \ +#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) \ __RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ - __RFF_FN(FailFast_IfWin32BoolFalseMsg) \ +#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ + __RFF_FN(FailFast_IfWin32BoolFalseMsg) \ (__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ +#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ +#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) \ - __RFF_FN(FailFast_HrIfMsg) \ - (__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ - __RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) \ - __RFF_FN(FailFast_GetLastErrorIfMsg) \ +#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) \ + __RFF_FN(FailFast_HrIfMsg) \ + (__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ + __RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) \ + __RFF_FN(FailFast_GetLastErrorIfMsg) \ (__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ +#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ +#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Always fail fast a known failure @@ -1256,12 +1269,13 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr) // Always fail fast a known failure - fail fast a var-arg message on failure -#define FAIL_FAST_MSG(fmt, ...) __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define FAIL_FAST_MSG(fmt, ...) \ + __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure -#define FAIL_FAST_IF_MSG(condition, fmt, ...) \ +#define FAIL_FAST_IF_MSG(condition, fmt, ...) \ __RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...) \ +#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...) \ __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) @@ -1274,33 +1288,33 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status) // Specializations -#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() \ - do \ - { \ - if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) \ - { \ - wil::details::g_pfnFailFastInLoaderCallout(); \ - } \ +#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() \ + do \ + { \ + if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) \ + { \ + wil::details::g_pfnFailFastInLoaderCallout(); \ + } \ } while ((void)0, 0) // Like 'FAIL_FAST_IF', but raises an assertion failure first for easier debugging -#define WI_FAIL_FAST_ASSERT(condition) \ - do \ - { \ - if (!wil::verify_bool(condition)) \ - { \ - WI_ASSERT_FAIL(#condition); \ - __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); \ - } \ +#define WI_FAIL_FAST_ASSERT(condition) \ + do \ + { \ + if (!wil::verify_bool(condition)) \ + { \ + WI_ASSERT_FAIL(#condition); \ + __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); \ + } \ } while (0, 0) -#define WI_FAIL_FAST_ASSERT_MSG(condition, msg) \ - do \ - { \ - if (!wil::verify_bool(condition)) \ - { \ - WI_ASSERT_FAIL(msg); \ - __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(#condition) __WI_CHECK_MSG_FMT(msg)); \ - } \ +#define WI_FAIL_FAST_ASSERT_MSG(condition, msg) \ + do \ + { \ + if (!wil::verify_bool(condition)) \ + { \ + WI_ASSERT_FAIL(msg); \ + __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(#condition) __WI_CHECK_MSG_FMT(msg)); \ + } \ } while (0, 0) //***************************************************************************** @@ -1318,50 +1332,57 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // Conditionally throw failures - returns parameter value #define THROW_IF_FAILED(hr) __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) \ + __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) #define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err) #define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr) -#define THROW_HR_IF(hr, condition) __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define THROW_HR_IF(hr, condition) \ + __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) #define THROW_HR_IF_NULL(hr, ptr) __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) -#define THROW_WIN32_IF(win32err, condition) \ +#define THROW_WIN32_IF(win32err, condition) \ __R_FN(Throw_Win32If)(__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition)) #define THROW_LAST_ERROR_IF(condition) __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) #define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) #define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status) // Always throw a known failure - throw a var-arg message on failure -#define THROW_HR_MSG(hr, fmt, ...) \ +#define THROW_HR_MSG(hr, fmt, ...) \ __R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_MSG(fmt, ...) __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_WIN32_MSG(win32err, fmt, ...) \ +#define THROW_LAST_ERROR_MSG(fmt, ...) \ + __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define THROW_WIN32_MSG(win32err, fmt, ...) \ __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_EXCEPTION_MSG(exception, fmt, ...) \ - wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_NTSTATUS_MSG(status, fmt, ...) \ +#define THROW_EXCEPTION_MSG(exception, fmt, ...) \ + wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define THROW_NTSTATUS_MSG(status, fmt, ...) \ __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Conditionally throw failures - returns parameter value - throw a var-arg message on failure -#define THROW_IF_FAILED_MSG(hr, fmt, ...) \ +#define THROW_IF_FAILED_MSG(hr, fmt, ...) \ __R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ - __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ +#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \ + __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \ __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ +#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \ __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_HR_IF_MSG(hr, condition, fmt, ...) \ - __R_FN(Throw_HrIfMsg) \ +#define THROW_HR_IF_MSG(hr, condition, fmt, ...) \ + __R_FN(Throw_HrIfMsg) \ (__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ +#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \ __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_WIN32_IF_MSG(win32err, condition, fmt, ...) \ - __R_FN(Throw_Win32IfMsg) \ - (__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) \ - __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ +#define THROW_WIN32_IF_MSG(win32err, condition, fmt, ...) \ + __R_FN(Throw_Win32IfMsg) \ + (__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) \ + __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), \ + __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) +#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \ __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ +#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \ __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) //***************************************************************************** @@ -1370,88 +1391,89 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") // Use these macros *within* a catch (...) block to handle exceptions #define RETURN_CAUGHT_EXCEPTION() return __R_FN(Return_CaughtException)(__R_INFO_ONLY(nullptr)) -#define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) \ +#define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) \ return __R_FN(Return_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) #define RETURN_CAUGHT_EXCEPTION_EXPECTED() return wil::ResultFromCaughtException() #define LOG_CAUGHT_EXCEPTION() __R_FN(Log_CaughtException)(__R_INFO_ONLY(nullptr)) -#define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...) \ +#define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...) \ __R_FN(Log_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) #define FAIL_FAST_CAUGHT_EXCEPTION() __R_FN(FailFast_CaughtException)(__R_INFO_ONLY(nullptr)) -#define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...) \ +#define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...) \ __R_FN(FailFast_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) #define THROW_NORMALIZED_CAUGHT_EXCEPTION() __R_FN(Throw_CaughtException)(__R_INFO_ONLY(nullptr)) -#define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...) \ +#define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...) \ __R_FN(Throw_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) // Use these macros in place of a catch block to handle exceptions -#define CATCH_RETURN() \ - catch (...) \ - { \ - RETURN_CAUGHT_EXCEPTION(); \ +#define CATCH_RETURN() \ + catch (...) \ + { \ + RETURN_CAUGHT_EXCEPTION(); \ } -#define CATCH_RETURN_MSG(fmt, ...) \ - catch (...) \ - { \ - RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ +#define CATCH_RETURN_MSG(fmt, ...) \ + catch (...) \ + { \ + RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ } -#define CATCH_RETURN_EXPECTED() \ - catch (...) \ - { \ - RETURN_CAUGHT_EXCEPTION_EXPECTED(); \ +#define CATCH_RETURN_EXPECTED() \ + catch (...) \ + { \ + RETURN_CAUGHT_EXCEPTION_EXPECTED(); \ } -#define CATCH_LOG() \ - catch (...) \ - { \ - LOG_CAUGHT_EXCEPTION(); \ +#define CATCH_LOG() \ + catch (...) \ + { \ + LOG_CAUGHT_EXCEPTION(); \ } -// Use CATCH_LOG_RETURN instead of CATCH_LOG in a function-try block around a destructor. CATCH_LOG in this specific case has an -// implicit throw at the end of scope. Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept throws exception) is -// detected even when the throwing code is unreachable, such as the end of scope after a return, in function-level catch. -#define CATCH_LOG_RETURN() \ - catch (...) \ - { \ - __pragma(warning(suppress : 4297)); \ - LOG_CAUGHT_EXCEPTION(); \ - return; \ +// Use CATCH_LOG_RETURN instead of CATCH_LOG in a function-try block around a destructor. CATCH_LOG in this specific +// case has an implicit throw at the end of scope. Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept +// throws exception) is detected even when the throwing code is unreachable, such as the end of scope after a return, in +// function-level catch. +#define CATCH_LOG_RETURN() \ + catch (...) \ + { \ + __pragma(warning(suppress : 4297)); \ + LOG_CAUGHT_EXCEPTION(); \ + return; \ } -#define CATCH_LOG_MSG(fmt, ...) \ - catch (...) \ - { \ - LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ +#define CATCH_LOG_MSG(fmt, ...) \ + catch (...) \ + { \ + LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ } // Likewise use CATCH_LOG_RETURN_MSG instead of CATCH_LOG_MSG in function-try blocks around destructors. -#define CATCH_LOG_RETURN_MSG(fmt, ...) \ - catch (...) \ - { \ - __pragma(warning(suppress : 4297)); \ - LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ - return; \ +#define CATCH_LOG_RETURN_MSG(fmt, ...) \ + catch (...) \ + { \ + __pragma(warning(suppress : 4297)); \ + LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ + return; \ } -#define CATCH_FAIL_FAST() \ - catch (...) \ - { \ - FAIL_FAST_CAUGHT_EXCEPTION(); \ +#define CATCH_FAIL_FAST() \ + catch (...) \ + { \ + FAIL_FAST_CAUGHT_EXCEPTION(); \ } -#define CATCH_FAIL_FAST_MSG(fmt, ...) \ - catch (...) \ - { \ - FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ +#define CATCH_FAIL_FAST_MSG(fmt, ...) \ + catch (...) \ + { \ + FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ } -#define CATCH_THROW_NORMALIZED() \ - catch (...) \ - { \ - THROW_NORMALIZED_CAUGHT_EXCEPTION(); \ +#define CATCH_THROW_NORMALIZED() \ + catch (...) \ + { \ + THROW_NORMALIZED_CAUGHT_EXCEPTION(); \ } -#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) \ - catch (...) \ - { \ - THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ +#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) \ + catch (...) \ + { \ + THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \ } -#define CATCH_LOG_RETURN_HR(hr) \ - catch (...) \ - { \ - LOG_CAUGHT_EXCEPTION(); \ - return hr; \ +#define CATCH_LOG_RETURN_HR(hr) \ + catch (...) \ + { \ + LOG_CAUGHT_EXCEPTION(); \ + return hr; \ } #endif // WIL_ENABLE_EXCEPTIONS @@ -1468,49 +1490,50 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define WI_USAGE_ASSERT_STOP(condition) WI_ASSERT(condition) #endif #ifdef RESULT_DEBUG -#define WI_USAGE_ERROR(msg, ...) \ - do \ - { \ - LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); \ - WI_USAGE_ASSERT_STOP(false); \ +#define WI_USAGE_ERROR(msg, ...) \ + do \ + { \ + LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); \ + WI_USAGE_ASSERT_STOP(false); \ } while ((void)0, 0) -#define WI_USAGE_ERROR_FORWARD(msg, ...) \ - do \ - { \ - ReportFailure_ReplaceMsg(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); \ - WI_USAGE_ASSERT_STOP(false); \ +#define WI_USAGE_ERROR_FORWARD(msg, ...) \ + do \ + { \ + ReportFailure_ReplaceMsg(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, \ + ##__VA_ARGS__); \ + WI_USAGE_ASSERT_STOP(false); \ } while ((void)0, 0) #else -#define WI_USAGE_ERROR(msg, ...) \ - do \ - { \ - LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \ - WI_USAGE_ASSERT_STOP(false); \ +#define WI_USAGE_ERROR(msg, ...) \ + do \ + { \ + LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \ + WI_USAGE_ASSERT_STOP(false); \ } while ((void)0, 0) -#define WI_USAGE_ERROR_FORWARD(msg, ...) \ - do \ - { \ - ReportFailure_Hr(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \ - WI_USAGE_ASSERT_STOP(false); \ +#define WI_USAGE_ERROR_FORWARD(msg, ...) \ + do \ + { \ + ReportFailure_Hr(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \ + WI_USAGE_ASSERT_STOP(false); \ } while ((void)0, 0) #endif -#define WI_USAGE_VERIFY(condition, msg, ...) \ - do \ - { \ - const auto __passed = wil::verify_bool(condition); \ - if (!__passed) \ - { \ - WI_USAGE_ERROR(msg, ##__VA_ARGS__); \ - } \ +#define WI_USAGE_VERIFY(condition, msg, ...) \ + do \ + { \ + const auto __passed = wil::verify_bool(condition); \ + if (!__passed) \ + { \ + WI_USAGE_ERROR(msg, ##__VA_ARGS__); \ + } \ } while ((void)0, 0) -#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) \ - do \ - { \ - const auto __passed = wil::verify_bool(condition); \ - if (!__passed) \ - { \ - WI_USAGE_ERROR_FORWARD(msg, ##__VA_ARGS__); \ - } \ +#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) \ + do \ + { \ + const auto __passed = wil::verify_bool(condition); \ + if (!__passed) \ + { \ + WI_USAGE_ERROR_FORWARD(msg, ##__VA_ARGS__); \ + } \ } while ((void)0, 0) #ifdef RESULT_DEBUG #define WI_USAGE_ASSERT(condition, msg, ...) WI_USAGE_VERIFY(condition, msg, ##__VA_ARGS__) @@ -1534,58 +1557,58 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") #define __WIL_PRIVATE_FAIL_FAST_HR(hr) FAIL_FAST_HR(hr) #define __WIL_PRIVATE_LOG_HR(hr) LOG_HR(hr) #else -#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) \ - do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - __RETURN_HR_FAIL_NOFILE(__hrRet, #hr); \ - } \ +#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) \ + do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + __RETURN_HR_FAIL_NOFILE(__hrRet, #hr); \ + } \ } while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) \ - do \ - { \ - if (wil::verify_bool(cond)) \ - { \ - __RETURN_HR_NOFILE(wil::verify_hresult(hr), #cond); \ - } \ +#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) \ + do \ + { \ + if (wil::verify_bool(cond)) \ + { \ + __RETURN_HR_NOFILE(wil::verify_hresult(hr), #cond); \ + } \ } while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) \ - do \ - { \ - if (wil::verify_bool(cond)) \ - { \ - __RETURN_GLE_FAIL_NOFILE(#cond); \ - } \ +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) \ + do \ + { \ + if (wil::verify_bool(cond)) \ + { \ + __RETURN_GLE_FAIL_NOFILE(#cond); \ + } \ } while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \ - do \ - { \ - const BOOL __boolRet = wil::verify_BOOL(win32BOOL); \ - if (!__boolRet) \ - { \ - __RETURN_GLE_FAIL_NOFILE(#win32BOOL); \ - } \ +#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \ + do \ + { \ + const BOOL __boolRet = wil::verify_BOOL(win32BOOL); \ + if (!__boolRet) \ + { \ + __RETURN_GLE_FAIL_NOFILE(#win32BOOL); \ + } \ } while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) \ - do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_GLE_FAIL_NOFILE(#ptr); \ - } \ +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) \ + do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_GLE_FAIL_NOFILE(#ptr); \ + } \ } while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) \ - do \ - { \ - if ((ptr) == nullptr) \ - { \ - __RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); \ - } \ +#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) \ + do \ + { \ + if ((ptr) == nullptr) \ + { \ + __RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); \ + } \ } while ((void)0, 0) #define __WIL_PRIVATE_RETURN_LAST_ERROR() __RETURN_GLE_FAIL_NOFILE(nullptr) -#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) \ +#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) \ __RFF_FN(FailFast_HrIf)(__RFF_INFO_NOFILE(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) #define __WIL_PRIVATE_FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO_NOFILE(#hr) wil::verify_hresult(hr)) #define __WIL_PRIVATE_LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO_NOFILE(#hr) wil::verify_hresult(hr)) @@ -1594,2102 +1617,2126 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0") namespace wil { -// Indicates the kind of message / failure type that was used to produce a given error -enum class FailureType -{ - Exception, // THROW_... - Return, // RETURN_..._LOG or RETURN_..._MSG - Log, // LOG_... - FailFast // FAIL_FAST_... -}; - -enum class FailureFlags -{ - None = 0x00, - RequestFailFast = 0x01, - RequestSuppressTelemetry = 0x02, - RequestDebugBreak = 0x04, - NtStatus = 0x08, -}; -DEFINE_ENUM_FLAG_OPERATORS(FailureFlags); - -/** Use with functions and macros that allow customizing which kinds of exceptions are handled. -This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */ -enum class SupportedExceptions -{ - Default, //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions). - Known, //!< [Known] all well known exceptions (including std::exception). - All, //!< [All] all exceptions, known or otherwise. - None, //!< [None] no exceptions at all, an exception will fail-fast where thrown. - Thrown, //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException). - ThrownOrAlloc //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or std::bad_alloc. -}; - -// Represents the call context information about a given failure -// No constructors, destructors or virtual members should be contained within -struct CallContextInfo -{ - long contextId; // incrementing ID for this call context (unique across an individual module load within process) - PCSTR contextName; // the explicit name given to this context - PCWSTR contextMessage; // [optional] Message that can be associated with the call context -}; - -// Represents all context information about a given failure -// No constructors, destructors or virtual members should be contained within -struct FailureInfo -{ - FailureType type; - FailureFlags flags; - HRESULT hr; - NTSTATUS status; - long failureId; // incrementing ID for this specific failure (unique across an individual module load within process) - PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message) - DWORD threadId; // the thread this failure was originally encountered on - PCSTR pszCode; // [debug only] Capture code from the macro - PCSTR pszFunction; // [debug only] The function name - PCSTR pszFile; - unsigned int uLineNumber; - int cFailureCount; // How many failures of 'type' have been reported in this module so far - PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure - CallContextInfo callContextOriginating; // The outermost (first seen) call context - CallContextInfo callContextCurrent; // The most recently seen call context - PCSTR pszModule; // The module where the failure originated - void* returnAddress; // The return address to the point that called the macro - void* callerReturnAddress; // The return address of the function that includes the macro -}; - -//! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions. -//! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions as parameters -//! hidden behind a macro. In some cases, the user needs to directly supply these, so this class provides the mechanism for that. -//! We only use this for user-passed content as it can't be directly controlled by RESULT_DIAGNOSTICS_LEVEL to ensure there are no -//! ODR violations (though that variable still controls what parameters within this structure would be available). -struct DiagnosticsInfo -{ - void* returnAddress = nullptr; - PCSTR file = nullptr; - PCSTR name = nullptr; - unsigned short line = 0; - - DiagnosticsInfo() = default; - - __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_) : - returnAddress(returnAddress_), file(file_), line(line_) + // Indicates the kind of message / failure type that was used to produce a given error + enum class FailureType { - } + Exception, // THROW_... + Return, // RETURN_..._LOG or RETURN_..._MSG + Log, // LOG_... + FailFast // FAIL_FAST_... + }; - __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) : - returnAddress(returnAddress_), file(file_), name(name_), line(line_) + enum class FailureFlags { - } -}; + None = 0x00, + RequestFailFast = 0x01, + RequestSuppressTelemetry = 0x02, + RequestDebugBreak = 0x04, + NtStatus = 0x08, + }; + DEFINE_ENUM_FLAG_OPERATORS(FailureFlags); -enum class ErrorReturn -{ - Auto, - None -}; - -/// @cond -namespace details -{ - // 'FARPROC' is declared in such a way that it cannot safely be assumed cast-able to other function pointer types. - // This function helps alleviate warnings that can arise from this - template - inline FuncPtr GetProcAddress(_In_ HMODULE module, _In_ LPCSTR procName) WI_NOEXCEPT + /** Use with functions and macros that allow customizing which kinds of exceptions are handled. + This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */ + enum class SupportedExceptions { - return reinterpret_cast(reinterpret_cast(::GetProcAddress(module, procName))); - } -} // namespace details -/// @endcond + Default, //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions). + Known, //!< [Known] all well known exceptions (including std::exception). + All, //!< [All] all exceptions, known or otherwise. + None, //!< [None] no exceptions at all, an exception will fail-fast where thrown. + Thrown, //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException). + ThrownOrAlloc //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or + //!< std::bad_alloc. + }; -// [optionally] Plug in error logging -// Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or -// SetResultLoggingCallback for observation. -extern "C" __declspec(selectany) void(__stdcall* g_pfnResultLoggingCallback)( - _Inout_ wil::FailureInfo* pFailure, - _Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage, - _Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_PFN_NOEXCEPT = nullptr; - -// [optional] -// This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can also -// be set directly from within the debugger to force console logging for debugging purposes. -__declspec(selectany) bool g_fResultOutputDebugString = true; - -// [optionally] Allows application to specify a debugger to detect whether a debugger is present. -// Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns -// false. -__declspec(selectany) bool(__stdcall* g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr; - -// [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached and ::IsDebuggerPresent returns false -__declspec(selectany) bool g_fIsDebuggerPresent = false; - -// [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception) -__declspec(selectany) HRESULT(__stdcall* g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr; - -// [optionally] Use to configure fast fail of unknown exceptions (turn them off). -__declspec(selectany) bool g_fResultFailFastUnknownExceptions = true; - -// [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^ -__declspec(selectany) bool g_fResultThrowPlatformException = true; - -// [optionally] Set to false to a configure all CATCH_ and CAUGHT_ macros to NOT support (fail-fast) std::exception based exceptions (other than std::bad_alloc and wil::ResultException) -__declspec(selectany) bool g_fResultSupportStdException = true; - -// [optionally] Set to true to cause a debug break to occur on a result failure -__declspec(selectany) bool g_fBreakOnFailure = false; - -// [optionally] customize failfast behavior -__declspec(selectany) bool(__stdcall* g_pfnWilFailFast)(const wil::FailureInfo& info) WI_PFN_NOEXCEPT = nullptr; - -/// @cond -namespace details -{ - // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function) - __declspec(selectany) bool g_resultMessageCallbackSet = false; - - // On Desktop/System WINAPI family: convert NTSTATUS error codes to friendly name strings. - __declspec(selectany) void(__stdcall* g_pfnFormatNtStatusMsg)(NTSTATUS, PWSTR, DWORD) = nullptr; - - _Success_(true) - _Ret_range_(dest, destEnd) - inline PWSTR LogStringPrintf( - _Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest, - _Pre_satisfies_(destEnd >= dest) PCWSTR destEnd, - _In_ _Printf_format_string_ PCWSTR format, - ...) + // Represents the call context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct CallContextInfo { - va_list argList; - va_start(argList, format); - StringCchVPrintfW(dest, (destEnd - dest), format, argList); - return (destEnd == dest) ? dest : (dest + wcslen(dest)); - } -} // namespace details -/// @endcond + long + contextId; // incrementing ID for this call context (unique across an individual module load within process) + PCSTR contextName; // the explicit name given to this context + PCWSTR contextMessage; // [optional] Message that can be associated with the call context + }; -// This call generates the default logging string that makes its way to OutputDebugString for -// any particular failure. This string is also used to associate a failure with a PlatformException^ which -// only allows a single string to be associated with the exception. -inline HRESULT GetFailureLogString( - _Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest, - _Pre_satisfies_(cchDest > 0) _In_ size_t cchDest, - _In_ FailureInfo const& failure) WI_NOEXCEPT -{ - // This function was lenient to empty strings at one point and some callers became dependent on this behavior - if ((cchDest == 0) || (pszDest == nullptr)) + // Represents all context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct FailureInfo { + FailureType type; + FailureFlags flags; + HRESULT hr; + NTSTATUS status; + long failureId; // incrementing ID for this specific failure (unique across an individual module load within + // process) + PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message) + DWORD threadId; // the thread this failure was originally encountered on + PCSTR pszCode; // [debug only] Capture code from the macro + PCSTR pszFunction; // [debug only] The function name + PCSTR pszFile; + unsigned int uLineNumber; + int cFailureCount; // How many failures of 'type' have been reported in this module so far + PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure + CallContextInfo callContextOriginating; // The outermost (first seen) call context + CallContextInfo callContextCurrent; // The most recently seen call context + PCSTR pszModule; // The module where the failure originated + void *returnAddress; // The return address to the point that called the macro + void *callerReturnAddress; // The return address of the function that includes the macro + }; + + //! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions. + //! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions + //! as parameters hidden behind a macro. In some cases, the user needs to directly supply these, so this class + //! provides the mechanism for that. We only use this for user-passed content as it can't be directly controlled by + //! RESULT_DIAGNOSTICS_LEVEL to ensure there are no ODR violations (though that variable still controls what + //! parameters within this structure would be available). + struct DiagnosticsInfo + { + void *returnAddress = nullptr; + PCSTR file = nullptr; + PCSTR name = nullptr; + unsigned short line = 0; + + DiagnosticsInfo() = default; + + __forceinline DiagnosticsInfo(void *returnAddress_, unsigned short line_, PCSTR file_) + : returnAddress(returnAddress_), file(file_), line(line_) + { + } + + __forceinline DiagnosticsInfo(void *returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) + : returnAddress(returnAddress_), file(file_), name(name_), line(line_) + { + } + }; + + enum class ErrorReturn + { + Auto, + None + }; + + /// @cond + namespace details + { + // 'FARPROC' is declared in such a way that it cannot safely be assumed cast-able to other function pointer + // types. This function helps alleviate warnings that can arise from this + template inline FuncPtr GetProcAddress(_In_ HMODULE module, _In_ LPCSTR procName) WI_NOEXCEPT + { + return reinterpret_cast(reinterpret_cast(::GetProcAddress(module, procName))); + } + } // namespace details + /// @endcond + + // [optionally] Plug in error logging + // Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or + // SetResultLoggingCallback for observation. + extern "C" __declspec(selectany) void(__stdcall *g_pfnResultLoggingCallback)( + _Inout_ wil::FailureInfo *pFailure, _Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage, + _Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_PFN_NOEXCEPT = nullptr; + + // [optional] + // This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can + // also be set directly from within the debugger to force console logging for debugging purposes. + __declspec(selectany) bool g_fResultOutputDebugString = true; + + // [optionally] Allows application to specify a debugger to detect whether a debugger is present. + // Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns + // false. + __declspec(selectany) bool(__stdcall *g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr; + + // [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached + // and ::IsDebuggerPresent returns false + __declspec(selectany) bool g_fIsDebuggerPresent = false; + + // [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception) + __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr; + + // [optionally] Use to configure fast fail of unknown exceptions (turn them off). + __declspec(selectany) bool g_fResultFailFastUnknownExceptions = true; + + // [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than + // Platform::Exception^ + __declspec(selectany) bool g_fResultThrowPlatformException = true; + + // [optionally] Set to false to a configure all CATCH_ and CAUGHT_ macros to NOT support (fail-fast) std::exception + // based exceptions (other than std::bad_alloc and wil::ResultException) + __declspec(selectany) bool g_fResultSupportStdException = true; + + // [optionally] Set to true to cause a debug break to occur on a result failure + __declspec(selectany) bool g_fBreakOnFailure = false; + + // [optionally] customize failfast behavior + __declspec(selectany) bool(__stdcall *g_pfnWilFailFast)(const wil::FailureInfo &info) WI_PFN_NOEXCEPT = nullptr; + + /// @cond + namespace details + { + // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function) + __declspec(selectany) bool g_resultMessageCallbackSet = false; + + // On Desktop/System WINAPI family: convert NTSTATUS error codes to friendly name strings. + __declspec(selectany) void(__stdcall *g_pfnFormatNtStatusMsg)(NTSTATUS, PWSTR, DWORD) = nullptr; + + _Success_(true) _Ret_range_(dest, destEnd) inline PWSTR + LogStringPrintf(_Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest, + _Pre_satisfies_(destEnd >= dest) PCWSTR destEnd, _In_ _Printf_format_string_ PCWSTR format, + ...) + { + va_list argList; + va_start(argList, format); + StringCchVPrintfW(dest, (destEnd - dest), format, argList); + return (destEnd == dest) ? dest : (dest + wcslen(dest)); + } + } // namespace details + /// @endcond + + // This call generates the default logging string that makes its way to OutputDebugString for + // any particular failure. This string is also used to associate a failure with a PlatformException^ which + // only allows a single string to be associated with the exception. + inline HRESULT GetFailureLogString(_Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest, + _Pre_satisfies_(cchDest > 0) _In_ size_t cchDest, + _In_ FailureInfo const &failure) WI_NOEXCEPT + { + // This function was lenient to empty strings at one point and some callers became dependent on this behavior + if ((cchDest == 0) || (pszDest == nullptr)) + { + return S_OK; + } + + pszDest[0] = L'\0'; + + // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the + // console or the platform exception object if the caller desires it. + if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet) + { + // older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be + // modifying + g_pfnResultLoggingCallback(const_cast(&failure), pszDest, cchDest); + } + + // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we + // still want it for OutputDebugString or exception message, then generate the default string. + if (pszDest[0] == L'\0') + { + PCSTR pszType = ""; + switch (failure.type) + { + case FailureType::Exception: + pszType = "Exception"; + break; + case FailureType::Return: + if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) + { + pszType = "ReturnNt"; + } + else + { + pszType = "ReturnHr"; + } + break; + case FailureType::Log: + if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) + { + pszType = "LogNt"; + } + else + { + pszType = "LogHr"; + } + break; + case FailureType::FailFast: + pszType = "FailFast"; + break; + } + + wchar_t szErrorText[256]{}; + LONG errorCode = 0; + + if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) + { + errorCode = failure.status; + if (wil::details::g_pfnFormatNtStatusMsg) + { + wil::details::g_pfnFormatNtStatusMsg(failure.status, szErrorText, ARRAYSIZE(szErrorText)); + } + } + else + { + errorCode = failure.hr; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, failure.hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErrorText, ARRAYSIZE(szErrorText), nullptr); + } + + // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage + // %Caller_MSG [%CODE(%FUNCTION)] + + PWSTR dest = pszDest; + PCWSTR destEnd = (pszDest + cchDest); + + if (failure.pszFile != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, + failure.uLineNumber, failure.pszModule, failure.returnAddress); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress); + } + + if (failure.callerReturnAddress != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress); + } + + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, + ::GetCurrentThreadId(), errorCode, szErrorText); + + if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || + (failure.pszFunction != nullptr)) + { + dest = details::LogStringPrintf(dest, destEnd, L" "); + if (failure.pszMessage != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage); + } + if (failure.pszCallContext != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext); + } + + if (failure.pszCode != nullptr) + { + dest = + details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode); + } + else if (failure.pszFunction != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"\n"); + } + } + } + + // Explicitly choosing to return success in the event of truncation... Current callers + // depend upon it or it would be eliminated. return S_OK; } - pszDest[0] = L'\0'; - - // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console - // or the platform exception object if the caller desires it. - if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet) + /// @cond + namespace details { - // older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be modifying - g_pfnResultLoggingCallback(const_cast(&failure), pszDest, cchDest); - } - - // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want - // it for OutputDebugString or exception message, then generate the default string. - if (pszDest[0] == L'\0') - { - PCSTR pszType = ""; - switch (failure.type) + //! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context + //! where exceptions or errors can be observed and logged. + struct IFunctor { - case FailureType::Exception: - pszType = "Exception"; - break; - case FailureType::Return: - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - pszType = "ReturnNt"; - } - else - { - pszType = "ReturnHr"; - } - break; - case FailureType::Log: - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - pszType = "LogNt"; - } - else - { - pszType = "LogHr"; - } - break; - case FailureType::FailFast: - pszType = "FailFast"; - break; - } - - wchar_t szErrorText[256]{}; - LONG errorCode = 0; - - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - errorCode = failure.status; - if (wil::details::g_pfnFormatNtStatusMsg) - { - wil::details::g_pfnFormatNtStatusMsg(failure.status, szErrorText, ARRAYSIZE(szErrorText)); - } - } - else - { - errorCode = failure.hr; - FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - failure.hr, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - szErrorText, - ARRAYSIZE(szErrorText), - nullptr); - } - - // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage - // %Caller_MSG [%CODE(%FUNCTION)] - - PWSTR dest = pszDest; - PCWSTR destEnd = (pszDest + cchDest); - - if (failure.pszFile != nullptr) - { - dest = details::LogStringPrintf( - dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress); - } - else - { - dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress); - } - - if (failure.callerReturnAddress != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress); - } - - dest = details::LogStringPrintf( - dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), errorCode, szErrorText); - - if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr)) - { - dest = details::LogStringPrintf(dest, destEnd, L" "); - if (failure.pszMessage != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage); - } - if (failure.pszCallContext != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext); - } - - if (failure.pszCode != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode); - } - else if (failure.pszFunction != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction); - } - else - { - dest = details::LogStringPrintf(dest, destEnd, L"\n"); - } - } - } - - // Explicitly choosing to return success in the event of truncation... Current callers - // depend upon it or it would be eliminated. - return S_OK; -} - -/// @cond -namespace details -{ - //! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context where - //! exceptions or errors can be observed and logged. - struct IFunctor - { - virtual HRESULT Run() = 0; - }; - - //! Used to provide custom behavior when an exception is encountered while executing IFunctor - struct IFunctorHost - { - virtual HRESULT Run(IFunctor& functor) = 0; - virtual HRESULT ExceptionThrown(void* returnAddress) = 0; - }; - - __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT; - __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT) WI_NOEXCEPT; - - struct ResultStatus - { - enum class Kind : unsigned int - { - HResult, - NtStatus + virtual HRESULT Run() = 0; }; - static ResultStatus FromResult(const HRESULT _hr) + //! Used to provide custom behavior when an exception is encountered while executing IFunctor + struct IFunctorHost { - return {_hr, wil::details::HrToNtStatus(_hr), Kind::HResult}; - } - static ResultStatus FromStatus(const NTSTATUS _status) + virtual HRESULT Run(IFunctor &functor) = 0; + virtual HRESULT ExceptionThrown(void *returnAddress) = 0; + }; + + __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT; + __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT) WI_NOEXCEPT; + + struct ResultStatus { - return {wil::details::NtStatusToHr(_status), _status, Kind::NtStatus}; - } - static ResultStatus FromFailureInfo(const FailureInfo& _failure) - { - return {_failure.hr, _failure.status, WI_IsFlagSet(_failure.flags, FailureFlags::NtStatus) ? Kind::NtStatus : Kind::HResult}; - } - HRESULT hr = S_OK; - NTSTATUS status = STATUS_SUCCESS; - Kind kind = Kind::NtStatus; - }; - - // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback) - __declspec(selectany) void(__stdcall* g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - // Result.h plug-in (WIL use only) - __declspec(selectany) void(__stdcall* g_pfnNotifyFailure)(_Inout_ FailureInfo* pFailure) WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) void(__stdcall* g_pfnGetContextAndNotifyFailure)( - _Inout_ FailureInfo* pFailure, - _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_PFN_NOEXCEPT = nullptr; - - // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging - __declspec(selectany) void(__stdcall* g_pfnLoggingCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Module fetch function (automatically setup) - __declspec(selectany) PCSTR(__stdcall* g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Retrieve address offset and modulename - __declspec(selectany) bool(__stdcall* g_pfnGetModuleInformation)( - void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_PFN_NOEXCEPT = nullptr; - - // Called with the expectation that the program will terminate when called inside of a loader callout. - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) void(__stdcall* g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr; - - // Called to translate an NTSTATUS value to a Win32 error code - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) ULONG(__stdcall* g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Call to DebugBreak - __declspec(selectany) void(__stdcall* g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr; - - // Called to determine whether or not termination is happening - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) BOOLEAN(__stdcall* g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) bool g_processShutdownInProgress = false; - - // On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules - // that do not have RaiseFailFastException in kernelbase. UWP apps will directly link. - __declspec(selectany) void(__stdcall* g_pfnRaiseFailFastException)(PEXCEPTION_RECORD, PCONTEXT, DWORD) = nullptr; - - // Exception-based compiled additions - __declspec(selectany) HRESULT(__stdcall* g_pfnRunFunctorWithExceptionFilter)(IFunctor& functor, IFunctorHost& host, void* returnAddress) = nullptr; - __declspec(selectany) void(__stdcall* g_pfnRethrow)() = nullptr; - __declspec(selectany) void(__stdcall* g_pfnThrowResultException)(const FailureInfo& failure) = nullptr; - extern "C" __declspec(selectany) ResultStatus(__stdcall* g_pfnResultFromCaughtExceptionInternal)( - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, - _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - - // C++/WinRT additions - extern "C" __declspec(selectany) HRESULT(__stdcall* g_pfnResultFromCaughtException_CppWinRt)( - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, - _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - - // C++/cx compiled additions - extern "C" __declspec(selectany) void(__stdcall* g_pfnThrowPlatformException)(FailureInfo const& failure, PCWSTR debugString) = nullptr; - extern "C" __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall* g_pfnResultFromCaughtException_WinRt)( - _Inout_updates_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, - _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall* g_pfnResultFromKnownExceptions_WinRt)( - const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) = nullptr; - - // Plugin to call RoOriginateError (WIL use only) - __declspec(selectany) void(__stdcall* g_pfnOriginateCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - // Plugin to call RoFailFastWithErrorContext (WIL use only) - __declspec(selectany) void(__stdcall* g_pfnFailfastWithContextCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - // Allocate and disown the allocation so that Appverifier does not complain about a false leak - inline PVOID ProcessHeapAlloc(_In_ DWORD flags, _In_ size_t size) WI_NOEXCEPT - { - const HANDLE processHeap = ::GetProcessHeap(); - const PVOID allocation = ::HeapAlloc(processHeap, flags, size); - - static bool fetchedRtlDisownModuleHeapAllocation = false; - static NTSTATUS(__stdcall * pfnRtlDisownModuleHeapAllocation)(HANDLE, PVOID) WI_PFN_NOEXCEPT = nullptr; - - if (pfnRtlDisownModuleHeapAllocation) - { - (void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation); - } - else if (!fetchedRtlDisownModuleHeapAllocation) - { - if (auto ntdllModule = ::GetModuleHandleW(L"ntdll.dll")) + enum class Kind : unsigned int { - pfnRtlDisownModuleHeapAllocation = - details::GetProcAddress(ntdllModule, "RtlDisownModuleHeapAllocation"); + HResult, + NtStatus + }; + + static ResultStatus FromResult(const HRESULT _hr) + { + return {_hr, wil::details::HrToNtStatus(_hr), Kind::HResult}; } - fetchedRtlDisownModuleHeapAllocation = true; + static ResultStatus FromStatus(const NTSTATUS _status) + { + return {wil::details::NtStatusToHr(_status), _status, Kind::NtStatus}; + } + static ResultStatus FromFailureInfo(const FailureInfo &_failure) + { + return {_failure.hr, _failure.status, + WI_IsFlagSet(_failure.flags, FailureFlags::NtStatus) ? Kind::NtStatus : Kind::HResult}; + } + HRESULT hr = S_OK; + NTSTATUS status = STATUS_SUCCESS; + Kind kind = Kind::NtStatus; + }; + + // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback) + __declspec(selectany) void(__stdcall *g_pfnTelemetryCallback)( + bool alreadyReported, wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr; + + // Result.h plug-in (WIL use only) + __declspec(selectany) void(__stdcall *g_pfnNotifyFailure)(_Inout_ FailureInfo *pFailure) + WI_PFN_NOEXCEPT = nullptr; + __declspec(selectany) void(__stdcall *g_pfnGetContextAndNotifyFailure)( + _Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_PFN_NOEXCEPT = nullptr; + + // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); + // use with custom logging + __declspec(selectany) void(__stdcall *g_pfnLoggingCallback)(wil::FailureInfo const &failure) + WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Module fetch function (automatically setup) + __declspec(selectany) PCSTR(__stdcall *g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Retrieve address offset and modulename + __declspec(selectany) bool(__stdcall *g_pfnGetModuleInformation)(void *address, + _Out_opt_ unsigned int *addressOffset, + _Out_writes_bytes_opt_(size) char *name, + size_t size) WI_PFN_NOEXCEPT = nullptr; + + // Called with the expectation that the program will terminate when called inside of a loader callout. + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) void(__stdcall *g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr; + + // Called to translate an NTSTATUS value to a Win32 error code + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) ULONG(__stdcall *g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Call to DebugBreak + __declspec(selectany) void(__stdcall *g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr; + + // Called to determine whether or not termination is happening + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) BOOLEAN(__stdcall *g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr; + __declspec(selectany) bool g_processShutdownInProgress = false; + + // On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules + // that do not have RaiseFailFastException in kernelbase. UWP apps will directly link. + __declspec(selectany) void(__stdcall *g_pfnRaiseFailFastException)(PEXCEPTION_RECORD, PCONTEXT, + DWORD) = nullptr; + + // Exception-based compiled additions + __declspec(selectany) HRESULT(__stdcall *g_pfnRunFunctorWithExceptionFilter)(IFunctor &functor, + IFunctorHost &host, + void *returnAddress) = nullptr; + __declspec(selectany) void(__stdcall *g_pfnRethrow)() = nullptr; + __declspec(selectany) void(__stdcall *g_pfnThrowResultException)(const FailureInfo &failure) = nullptr; + extern "C" __declspec(selectany) ResultStatus(__stdcall *g_pfnResultFromCaughtExceptionInternal)( + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, + _Out_ bool *isNormalized) WI_PFN_NOEXCEPT = nullptr; + + // C++/WinRT additions + extern "C" __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException_CppWinRt)( + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, + _Out_ bool *isNormalized) WI_PFN_NOEXCEPT = nullptr; + + // C++/cx compiled additions + extern "C" __declspec(selectany) void(__stdcall *g_pfnThrowPlatformException)(FailureInfo const &failure, + PCWSTR debugString) = nullptr; + extern "C" __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) + HRESULT(__stdcall *g_pfnResultFromCaughtException_WinRt)( + _Inout_updates_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, + _Out_ bool *isNormalized) WI_PFN_NOEXCEPT = nullptr; + __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) + HRESULT(__stdcall *g_pfnResultFromKnownExceptions_WinRt)(const DiagnosticsInfo &diagnostics, + void *returnAddress, SupportedExceptions supported, + IFunctor &functor) = nullptr; + + // Plugin to call RoOriginateError (WIL use only) + __declspec(selectany) void(__stdcall *g_pfnOriginateCallback)(wil::FailureInfo const &failure) + WI_PFN_NOEXCEPT = nullptr; + + // Plugin to call RoFailFastWithErrorContext (WIL use only) + __declspec(selectany) void(__stdcall *g_pfnFailfastWithContextCallback)(wil::FailureInfo const &failure) + WI_PFN_NOEXCEPT = nullptr; + + // Allocate and disown the allocation so that Appverifier does not complain about a false leak + inline PVOID ProcessHeapAlloc(_In_ DWORD flags, _In_ size_t size) WI_NOEXCEPT + { + const HANDLE processHeap = ::GetProcessHeap(); + const PVOID allocation = ::HeapAlloc(processHeap, flags, size); + + static bool fetchedRtlDisownModuleHeapAllocation = false; + static NTSTATUS(__stdcall * pfnRtlDisownModuleHeapAllocation)(HANDLE, PVOID) WI_PFN_NOEXCEPT = nullptr; if (pfnRtlDisownModuleHeapAllocation) { (void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation); } + else if (!fetchedRtlDisownModuleHeapAllocation) + { + if (auto ntdllModule = ::GetModuleHandleW(L"ntdll.dll")) + { + pfnRtlDisownModuleHeapAllocation = + details::GetProcAddress( + ntdllModule, "RtlDisownModuleHeapAllocation"); + } + fetchedRtlDisownModuleHeapAllocation = true; + + if (pfnRtlDisownModuleHeapAllocation) + { + (void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation); + } + } + + return allocation; } - return allocation; - } - - enum class ReportFailureOptions - { - None = 0x00, - ForcePlatformException = 0x01, - MayRethrow = 0x02, - }; - DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions); - - template - using functor_return_type = decltype((*static_cast(nullptr))()); - - template - struct functor_wrapper_void : public IFunctor - { - TFunctor&& functor; - functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward(functor_)) + enum class ReportFailureOptions { - } + None = 0x00, + ForcePlatformException = 0x01, + MayRethrow = 0x02, + }; + DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions); + + template using functor_return_type = decltype((*static_cast(nullptr))()); + + template struct functor_wrapper_void : public IFunctor + { + TFunctor &&functor; + functor_wrapper_void(TFunctor &&functor_) : functor(wistd::forward(functor_)) + { + } #pragma warning(push) #pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2 - HRESULT Run() override - { - functor(); - return S_OK; - } + HRESULT Run() override + { + functor(); + return S_OK; + } #pragma warning(pop) - }; + }; - template - struct functor_wrapper_HRESULT : public IFunctor - { - TFunctor&& functor; - functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward(functor_)) + template struct functor_wrapper_HRESULT : public IFunctor { - } - HRESULT Run() override - { - return functor(); - } - }; + TFunctor &&functor; + functor_wrapper_HRESULT(TFunctor &functor_) : functor(wistd::forward(functor_)) + { + } + HRESULT Run() override + { + return functor(); + } + }; - template - struct functor_wrapper_other : public IFunctor - { - TFunctor&& functor; - TReturn& retVal; - functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward(functor_)), retVal(retval_) + template struct functor_wrapper_other : public IFunctor { - } + TFunctor &&functor; + TReturn &retVal; + functor_wrapper_other(TFunctor &functor_, TReturn &retval_) + : functor(wistd::forward(functor_)), retVal(retval_) + { + } #pragma warning(push) #pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2 - HRESULT Run() override - { - retVal = functor(); - return S_OK; - } + HRESULT Run() override + { + retVal = functor(); + return S_OK; + } #pragma warning(pop) - }; + }; - struct tag_return_void : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_void; - }; + struct tag_return_void : public wistd::integral_constant + { + template using functor_wrapper = functor_wrapper_void; + }; - struct tag_return_HRESULT : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_HRESULT; - }; + struct tag_return_HRESULT : public wistd::integral_constant + { + template using functor_wrapper = functor_wrapper_HRESULT; + }; - struct tag_return_other : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_other; - }; + struct tag_return_other : public wistd::integral_constant + { + template + using functor_wrapper = functor_wrapper_other; + }; - // type-trait to help discover the return type of a functor for tag/dispatch. + // type-trait to help discover the return type of a functor for tag/dispatch. - template - struct return_type - { - using type = tag_return_other; - }; + template struct return_type + { + using type = tag_return_other; + }; - template <> - struct return_type - { - using type = tag_return_HRESULT; - }; + template <> struct return_type + { + using type = tag_return_HRESULT; + }; - template <> - struct return_type - { - using type = tag_return_void; - }; + template <> struct return_type + { + using type = tag_return_void; + }; - template <> - struct return_type - { - using type = tag_return_void; - }; + template <> struct return_type + { + using type = tag_return_void; + }; - template - using functor_tag = typename return_type>::type; + template + using functor_tag = typename return_type>::type; - // Forward declarations to enable use of fail fast and reporting internally... - namespace __R_NS_NAME - { - _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT; - _Post_satisfies_(return == hr) - __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; - _Post_satisfies_(return == err) - __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; - } // namespace __R_NS_NAME - namespace __RFF_NS_NAME - { - __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT; - } // namespace __RFF_NS_NAME + // Forward declarations to enable use of fail fast and reporting internally... + namespace __R_NS_NAME + { + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT; + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + _Post_satisfies_(return == err) + __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + } // namespace __R_NS_NAME + namespace __RFF_NS_NAME + { + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, + FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT; + } // namespace __RFF_NS_NAME - RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& info); - inline void LogFailure( - __R_FN_PARAMS_FULL, - FailureType type, - const ResultStatus& resultPair, - _In_opt_ PCWSTR message, - bool fWantDebugString, - _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, - _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, - _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, - FailureFlags flags, - _Out_ FailureInfo* failure) WI_NOEXCEPT; + RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo &info); + inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus &resultPair, + _In_opt_ PCWSTR message, bool fWantDebugString, + _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, + _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, + _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, + FailureFlags flags, _Out_ FailureInfo *failure) WI_NOEXCEPT; - __declspec(noinline) inline void ReportFailure( - __R_FN_PARAMS_FULL, - FailureType type, - const ResultStatus& resultPair, - _In_opt_ PCWSTR message = nullptr, - ReportFailureOptions options = ReportFailureOptions::None); - template - __declspec(noinline) inline void ReportFailure_Base( - __R_FN_PARAMS_FULL, - const ResultStatus& resultPair, - _In_opt_ PCWSTR message = nullptr, - ReportFailureOptions options = ReportFailureOptions::None, - FailureFlags flags = FailureFlags::None); - template - inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...); - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr); - template - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, FailureFlags flags = FailureFlags::None); - template - __declspec(noinline) inline HRESULT ReportFailure_CaughtException( - __R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); + __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, + const ResultStatus &resultPair, + _In_opt_ PCWSTR message = nullptr, + ReportFailureOptions options = ReportFailureOptions::None); + template + __declspec(noinline) inline void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus &resultPair, + _In_opt_ PCWSTR message = nullptr, + ReportFailureOptions options = ReportFailureOptions::None, + FailureFlags flags = FailureFlags::None); + template + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, + ...); + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr); + template + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, + FailureFlags flags = FailureFlags::None); + template + __declspec(noinline) inline HRESULT ReportFailure_CaughtException( + __R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); //***************************************************************************** // Fail fast helpers (for use only internally to WIL) //***************************************************************************** /// @cond -#define __FAIL_FAST_ASSERT__(condition) \ - do \ - { \ - if (!(condition)) \ - { \ - __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); \ - } \ +#define __FAIL_FAST_ASSERT__(condition) \ + do \ + { \ + if (!(condition)) \ + { \ + __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); \ + } \ } while ((void)0, 0) -#define __FAIL_FAST_IMMEDIATE_ASSERT__(condition) \ - do \ - { \ - if (!(condition)) \ - { \ - wil::FailureInfo failure{}; \ - wil::details::WilFailFast(failure); \ - } \ +#define __FAIL_FAST_IMMEDIATE_ASSERT__(condition) \ + do \ + { \ + if (!(condition)) \ + { \ + wil::FailureInfo failure{}; \ + wil::details::WilFailFast(failure); \ + } \ } while ((void)0, 0) -#define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition) \ +#define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition) \ __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#condition) wil::verify_BOOL(condition)) - // A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages - // an allocated buffer and maintains the size. + // A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages + // an allocated buffer and maintains the size. - class shared_buffer - { - public: - shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + class shared_buffer { - } + public: + shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + { + } - shared_buffer(shared_buffer const& other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) - { - assign(other.m_pCopy, other.m_size); - } - - shared_buffer(shared_buffer&& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy), m_size(other.m_size) - { - other.m_pCopy = nullptr; - other.m_size = 0; - } - - ~shared_buffer() WI_NOEXCEPT - { - reset(); - } - - shared_buffer& operator=(shared_buffer const& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + shared_buffer(shared_buffer const &other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) { assign(other.m_pCopy, other.m_size); } - return *this; - } - shared_buffer& operator=(shared_buffer&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + shared_buffer(shared_buffer &&other) WI_NOEXCEPT : m_pCopy(other.m_pCopy), m_size(other.m_size) { - reset(); - m_pCopy = other.m_pCopy; - m_size = other.m_size; other.m_pCopy = nullptr; other.m_size = 0; } - return *this; - } - void reset() WI_NOEXCEPT - { - if (m_pCopy != nullptr) - { - if (0 == ::InterlockedDecrementRelease(m_pCopy)) - { - WIL_FreeMemory(m_pCopy); - } - m_pCopy = nullptr; - m_size = 0; - } - } - - bool create(_In_reads_bytes_opt_(cbData) void const* pData, size_t cbData) WI_NOEXCEPT - { - if (cbData == 0) + ~shared_buffer() WI_NOEXCEPT { reset(); + } + + shared_buffer &operator=(shared_buffer const &other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + assign(other.m_pCopy, other.m_size); + } + return *this; + } + + shared_buffer &operator=(shared_buffer &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_pCopy = other.m_pCopy; + m_size = other.m_size; + other.m_pCopy = nullptr; + other.m_size = 0; + } + return *this; + } + + void reset() WI_NOEXCEPT + { + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(m_pCopy)) + { + WIL_FreeMemory(m_pCopy); + } + m_pCopy = nullptr; + m_size = 0; + } + } + + bool create(_In_reads_bytes_opt_(cbData) void const *pData, size_t cbData) WI_NOEXCEPT + { + if (cbData == 0) + { + reset(); + return true; + } + + long *pCopyRefCount = reinterpret_cast(WIL_AllocateMemory(sizeof(long) + cbData)); + if (pCopyRefCount == nullptr) + { + return false; + } + + *pCopyRefCount = 0; + if (pData != nullptr) + { + memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter + } + assign(pCopyRefCount, cbData); return true; } - long* pCopyRefCount = reinterpret_cast(WIL_AllocateMemory(sizeof(long) + cbData)); - if (pCopyRefCount == nullptr) + bool create(size_t cbData) WI_NOEXCEPT { - return false; + return create(nullptr, cbData); } - *pCopyRefCount = 0; - if (pData != nullptr) + WI_NODISCARD void *get(_Out_opt_ size_t *pSize = nullptr) const WI_NOEXCEPT { - memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter + if (pSize != nullptr) + { + *pSize = m_size; + } + return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1); } - assign(pCopyRefCount, cbData); - return true; - } - bool create(size_t cbData) WI_NOEXCEPT - { - return create(nullptr, cbData); - } - - WI_NODISCARD void* get(_Out_opt_ size_t* pSize = nullptr) const WI_NOEXCEPT - { - if (pSize != nullptr) + WI_NODISCARD size_t size() const WI_NOEXCEPT { - *pSize = m_size; + return m_size; } - return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1); - } - WI_NODISCARD size_t size() const WI_NOEXCEPT - { - return m_size; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_pCopy != nullptr); - } - - WI_NODISCARD bool unique() const WI_NOEXCEPT - { - return ((m_pCopy != nullptr) && (*m_pCopy == 1)); - } - - private: - long* m_pCopy; // pointer to allocation: refcount + data - size_t m_size; // size of the data from m_pCopy - - void assign(_In_opt_ long* pCopy, size_t cbSize) WI_NOEXCEPT - { - reset(); - if (pCopy != nullptr) + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT { - m_pCopy = pCopy; - m_size = cbSize; - ::InterlockedIncrementNoFence(m_pCopy); + return (m_pCopy != nullptr); } - } - }; - inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void* pData, size_t countBytes) WI_NOEXCEPT - { - shared_buffer buffer; - buffer.create(pData, countBytes); - return buffer; - } - - inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT - { - shared_buffer buffer; - buffer.create(countBytes); - return buffer; - } - - // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is - // always simply contained within (it cannot be attached or detached). - - template - class shared_object - { - public: - shared_object() WI_NOEXCEPT : m_pCopy(nullptr) - { - } - - shared_object(shared_object const& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy) - { - if (m_pCopy != nullptr) + WI_NODISCARD bool unique() const WI_NOEXCEPT { - ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + return ((m_pCopy != nullptr) && (*m_pCopy == 1)); } - } - shared_object(shared_object&& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy) - { - other.m_pCopy = nullptr; - } + private: + long *m_pCopy; // pointer to allocation: refcount + data + size_t m_size; // size of the data from m_pCopy - ~shared_object() WI_NOEXCEPT - { - reset(); - } - - shared_object& operator=(shared_object const& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + void assign(_In_opt_ long *pCopy, size_t cbSize) WI_NOEXCEPT { reset(); - m_pCopy = other.m_pCopy; + if (pCopy != nullptr) + { + m_pCopy = pCopy; + m_size = cbSize; + ::InterlockedIncrementNoFence(m_pCopy); + } + } + }; + + inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void *pData, + size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(pData, countBytes); + return buffer; + } + + inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(countBytes); + return buffer; + } + + // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but + // is always simply contained within (it cannot be attached or detached). + + template class shared_object + { + public: + shared_object() WI_NOEXCEPT : m_pCopy(nullptr) + { + } + + shared_object(shared_object const &other) WI_NOEXCEPT : m_pCopy(other.m_pCopy) + { if (m_pCopy != nullptr) { ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); } } - return *this; - } - shared_object& operator=(shared_object&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + shared_object(shared_object &&other) WI_NOEXCEPT : m_pCopy(other.m_pCopy) { - reset(); - m_pCopy = other.m_pCopy; other.m_pCopy = nullptr; } - return *this; - } - void reset() WI_NOEXCEPT - { - if (m_pCopy != nullptr) + ~shared_object() WI_NOEXCEPT { - if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount)) + reset(); + } + + shared_object &operator=(shared_object const &other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) { - delete m_pCopy; + reset(); + m_pCopy = other.m_pCopy; + if (m_pCopy != nullptr) + { + ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + } } - m_pCopy = nullptr; + return *this; } - } - bool create() - { - RefAndObject* pObject = new (std::nothrow) RefAndObject(); - if (pObject == nullptr) + shared_object &operator=(shared_object &&other) WI_NOEXCEPT { - return false; + if (this != wistd::addressof(other)) + { + reset(); + m_pCopy = other.m_pCopy; + other.m_pCopy = nullptr; + } + return *this; } - reset(); - m_pCopy = pObject; - return true; - } - template - bool create(param_t&& param1) - { - RefAndObject* pObject = new (std::nothrow) RefAndObject(wistd::forward(param1)); - if (pObject == nullptr) + void reset() WI_NOEXCEPT { - return false; + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount)) + { + delete m_pCopy; + } + m_pCopy = nullptr; + } } - reset(); - m_pCopy = pObject; - return true; - } - WI_NODISCARD object_t* get() const WI_NOEXCEPT - { - return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_pCopy != nullptr); - } - - WI_NODISCARD bool unique() const WI_NOEXCEPT - { - return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1)); - } - - WI_NODISCARD object_t* operator->() const WI_NOEXCEPT - { - return get(); - } - - private: - struct RefAndObject - { - long m_refCount; - object_t m_object; - - RefAndObject() : m_refCount(1), m_object() + bool create() { + RefAndObject *pObject = new (std::nothrow) RefAndObject(); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; } - template - RefAndObject(param_t&& param1) : m_refCount(1), m_object(wistd::forward(param1)) + template bool create(param_t &¶m1) { + RefAndObject *pObject = new (std::nothrow) RefAndObject(wistd::forward(param1)); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; } + + WI_NODISCARD object_t *get() const WI_NOEXCEPT + { + return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object; + } + + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT + { + return (m_pCopy != nullptr); + } + + WI_NODISCARD bool unique() const WI_NOEXCEPT + { + return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1)); + } + + WI_NODISCARD object_t *operator->() const WI_NOEXCEPT + { + return get(); + } + + private: + struct RefAndObject + { + long m_refCount; + object_t m_object; + + RefAndObject() : m_refCount(1), m_object() + { + } + + template + RefAndObject(param_t &¶m1) : m_refCount(1), m_object(wistd::forward(param1)) + { + } + }; + + RefAndObject *m_pCopy; }; - RefAndObject* m_pCopy; - }; - - // The following functions are basically the same, but are kept separated to: - // 1) Provide a unique count and last error code per-type - // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based - // upon count of errors from a particular type, etc) - __WI_PUSH_WARNINGS + // The following functions are basically the same, but are kept separated to: + // 1) Provide a unique count and last error code per-type + // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based + // upon count of errors from a particular type, etc) + __WI_PUSH_WARNINGS #if __clang_major__ >= 13 - __WI_CLANG_DISABLE_WARNING(-Wunused-but-set-variable) // s_hrErrorLast used for debugging. We intentionally only assign to it + __WI_CLANG_DISABLE_WARNING(-Wunused - but - set - + variable) // s_hrErrorLast used for debugging. We intentionally only assign to it #endif - __WI_MSVC_DISABLE_WARNING(4746) // s_hrErrorLast' is subject to /volatile: setting; consider using __iso_volatile_load/store intrinsic functions + __WI_MSVC_DISABLE_WARNING(4746) // s_hrErrorLast' is subject to /volatile: setting; consider using + // __iso_volatile_load/store intrinsic functions - __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - s_hrErrorLast = hr; - return 1; - } - __WI_POP_WARNINGS - - inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags) - { - // if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.) - // or via direct linkage (e.g. UWP apps), then use it. - if (g_pfnRaiseFailFastException) + __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT { - g_pfnRaiseFailFastException(er, cr, flags); + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + s_hrErrorLast = hr; + return 1; + } + __WI_POP_WARNINGS + + inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, + _In_ DWORD flags) + { + // if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP + // etc.) or via direct linkage (e.g. UWP apps), then use it. + if (g_pfnRaiseFailFastException) + { + g_pfnRaiseFailFastException(er, cr, flags); + } + // if not, as a best effort, we are just going to call the intrinsic. + __fastfail(FAST_FAIL_FATAL_APP_EXIT); } - // if not, as a best effort, we are just going to call the intrinsic. - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - inline bool __stdcall GetModuleInformation( - _In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_NOEXCEPT - { - HMODULE hModule = nullptr; - if (address && !GetModuleHandleExW( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast(address), - &hModule)) + inline bool __stdcall GetModuleInformation(_In_opt_ void *address, _Out_opt_ unsigned int *addressOffset, + _Out_writes_bytes_opt_(size) char *name, size_t size) WI_NOEXCEPT { - assign_to_opt_param(addressOffset, 0U); - return false; - } - if (addressOffset) - { - *addressOffset = - address ? static_cast(static_cast(address) - reinterpret_cast(hModule)) - : 0; - } - if (name) - { - char modulePath[MAX_PATH]; - if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath))) + HMODULE hModule = nullptr; + if (address && !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(address), &hModule)) { + assign_to_opt_param(addressOffset, 0U); return false; } - - PCSTR start = modulePath + strlen(modulePath); - while ((start > modulePath) && (*(start - 1) != '\\')) + if (addressOffset) { - start--; + *addressOffset = address ? static_cast(static_cast(address) - + reinterpret_cast(hModule)) + : 0; } - StringCchCopyA(name, size, start); - } - return true; - } + if (name) + { + char modulePath[MAX_PATH]; + if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath))) + { + return false; + } - __WI_PUSH_WARNINGS - __WI_MSVC_DISABLE_WARNING(4746) // s_fModuleValid' is subject to /volatile: setting; consider using __iso_volatile_load/store intrinsic functions - inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT - { - static char s_szModule[64] = {}; - static volatile bool s_fModuleValid = false; - if (!s_fModuleValid) // Races are acceptable + PCSTR start = modulePath + strlen(modulePath); + while ((start > modulePath) && (*(start - 1) != '\\')) + { + start--; + } + StringCchCopyA(name, size, start); + } + return true; + } + + __WI_PUSH_WARNINGS + __WI_MSVC_DISABLE_WARNING(4746) // s_fModuleValid' is subject to /volatile: setting; consider using + // __iso_volatile_load/store intrinsic functions + inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT { - GetModuleInformation(reinterpret_cast(&RecordFailFast), nullptr, s_szModule, ARRAYSIZE(s_szModule)); - s_fModuleValid = true; + static char s_szModule[64] = {}; + static volatile bool s_fModuleValid = false; + if (!s_fModuleValid) // Races are acceptable + { + GetModuleInformation(reinterpret_cast(&RecordFailFast), nullptr, s_szModule, + ARRAYSIZE(s_szModule)); + s_fModuleValid = true; + } + return s_szModule; } - return s_szModule; - } - __WI_POP_WARNINGS + __WI_POP_WARNINGS - inline void __stdcall DebugBreak() WI_NOEXCEPT - { - ::DebugBreak(); - } - - inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags) - { - auto k32handle = GetModuleHandleW(L"kernelbase.dll"); - _Analysis_assume_(k32handle != nullptr); - auto pfnRaiseFailFastException = - details::GetProcAddress(k32handle, "RaiseFailFastException"); - if (pfnRaiseFailFastException) + inline void __stdcall DebugBreak() WI_NOEXCEPT { - pfnRaiseFailFastException(er, cr, flags); + ::DebugBreak(); + } + + inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, + _In_ DWORD flags) + { + auto k32handle = GetModuleHandleW(L"kernelbase.dll"); + _Analysis_assume_(k32handle != nullptr); + auto pfnRaiseFailFastException = details::GetProcAddress( + k32handle, "RaiseFailFastException"); + if (pfnRaiseFailFastException) + { + pfnRaiseFailFastException(er, cr, flags); + } } - } #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - inline bool __stdcall GetModuleInformationFromAddress( - _In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* buffer, size_t size) WI_NOEXCEPT - { - if (size > 0) + inline bool __stdcall GetModuleInformationFromAddress(_In_opt_ void *address, + _Out_opt_ unsigned int *addressOffset, + _Out_writes_bytes_opt_(size) char *buffer, + size_t size) WI_NOEXCEPT { - assign_to_opt_param(buffer, '\0'); - } - if (addressOffset) - { - *addressOffset = 0; - } - if (g_pfnGetModuleInformation) - { - return g_pfnGetModuleInformation(address, addressOffset, buffer, size); - } - return false; - } - - __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT - { - // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb - if (SUCCEEDED_NTSTATUS(status)) - { - // All successful status codes have only one hresult equivalent, S_OK - return S_OK; - } - if (status == static_cast(STATUS_NO_MEMORY)) - { - // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping - return E_OUTOFMEMORY; - } - - if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr) - { - DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status); - - // ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to the Win32 error codes). - // There are known instances of this bug which are unlikely to be fixed soon, and it's always possible that additional instances - // could be added in the future. In these cases, it's better to use HRESULT_FROM_NT rather than returning a meaningless error. - if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND)) + if (size > 0) { - return __HRESULT_FROM_WIN32(err); + assign_to_opt_param(buffer, '\0'); } + if (addressOffset) + { + *addressOffset = 0; + } + if (g_pfnGetModuleInformation) + { + return g_pfnGetModuleInformation(address, addressOffset, buffer, size); + } + return false; } - return HRESULT_FROM_NT(status); - } - - __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT hr) WI_NOEXCEPT - { - // Constants taken from ntstatus.h - static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = 0xC000000D; - static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = 0xC00000E5; - static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = 0xC0000095; - static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A; - static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; - static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = 0xC0000002; - static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = 0x80000005; - static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B; - static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = 0xC0000273; - static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = 0xC0000161; - static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = 0xC0000163; - static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = 0xC0000023; - static constexpr NTSTATUS WIL_STATUS_DISK_FULL = 0xC000007F; - static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = 0xC0000033; - static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = 0xC0000135; - static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = 0xC0000059; - static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = 0xC000A083; - static constexpr HRESULT WIL_E_FAIL = 0x80004005; - - NTSTATUS status = STATUS_SUCCESS; - - switch (hr) + __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT { - case S_OK: - status = STATUS_SUCCESS; - break; - case E_INVALIDARG: - status = WIL_STATUS_INVALID_PARAMETER; - break; - case __HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR): - status = WIL_STATUS_INTERNAL_ERROR; - break; - case E_OUTOFMEMORY: - status = STATUS_NO_MEMORY; - break; - case __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW): - status = WIL_STATUS_INTEGER_OVERFLOW; - break; - case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND): - status = WIL_STATUS_OBJECT_PATH_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): - status = WIL_STATUS_OBJECT_NAME_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION): - status = WIL_STATUS_NOT_IMPLEMENTED; - break; - case __HRESULT_FROM_WIN32(ERROR_MORE_DATA): - status = WIL_STATUS_BUFFER_OVERFLOW; - break; - case __HRESULT_FROM_WIN32(ERROR_IMPLEMENTATION_LIMIT): - status = WIL_STATUS_IMPLEMENTATION_LIMIT; - break; - case __HRESULT_FROM_WIN32(ERROR_NO_MORE_MATCHES): - status = WIL_STATUS_NO_MORE_MATCHES; - break; - case __HRESULT_FROM_WIN32(ERROR_ILLEGAL_CHARACTER): - status = WIL_STATUS_ILLEGAL_CHARACTER; - break; - case __HRESULT_FROM_WIN32(ERROR_UNDEFINED_CHARACTER): - status = WIL_STATUS_UNDEFINED_CHARACTER; - break; - case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): - status = WIL_STATUS_BUFFER_TOO_SMALL; - break; - case __HRESULT_FROM_WIN32(ERROR_DISK_FULL): - status = WIL_STATUS_DISK_FULL; - break; - case __HRESULT_FROM_WIN32(ERROR_INVALID_NAME): - status = WIL_STATUS_OBJECT_NAME_INVALID; - break; - case __HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND): - status = WIL_STATUS_DLL_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION): - status = WIL_STATUS_REVISION_MISMATCH; - break; - case WIL_E_FAIL: - status = STATUS_UNSUCCESSFUL; - break; - case __HRESULT_FROM_WIN32(ERROR_XML_PARSE_ERROR): - status = WIL_STATUS_XML_PARSE_ERROR; - break; - case __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION): - status = STATUS_NONCONTINUABLE_EXCEPTION; - break; - default: - if ((hr & FACILITY_NT_BIT) != 0) + // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb + if (SUCCEEDED_NTSTATUS(status)) { - status = (hr & ~FACILITY_NT_BIT); + // All successful status codes have only one hresult equivalent, S_OK + return S_OK; } - else if (HRESULT_FACILITY(hr) == FACILITY_WIN32) + if (status == static_cast(STATUS_NO_MEMORY)) { - status = __NTSTATUS_FROM_WIN32(HRESULT_CODE(hr)); + // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error + // codes resulting in an unexpected mapping + return E_OUTOFMEMORY; } - else if (HRESULT_FACILITY(hr) == FACILITY_SSPI) + + if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr) { - status = - ((NTSTATUS)(hr) <= 0 ? ((NTSTATUS)(hr)) - : ((NTSTATUS)(((hr) & 0x0000FFFF) | (FACILITY_SSPI << 16) | ERROR_SEVERITY_ERROR))); + DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status); + + // ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to + // the Win32 error codes). There are known instances of this bug which are unlikely to be fixed soon, + // and it's always possible that additional instances could be added in the future. In these cases, it's + // better to use HRESULT_FROM_NT rather than returning a meaningless error. + if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND)) + { + return __HRESULT_FROM_WIN32(err); + } + } + + return HRESULT_FROM_NT(status); + } + + __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT hr) WI_NOEXCEPT + { + // Constants taken from ntstatus.h + static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = 0xC000000D; + static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = 0xC00000E5; + static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = 0xC0000095; + static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A; + static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; + static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = 0xC0000002; + static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = 0x80000005; + static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B; + static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = 0xC0000273; + static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = 0xC0000161; + static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = 0xC0000163; + static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = 0xC0000023; + static constexpr NTSTATUS WIL_STATUS_DISK_FULL = 0xC000007F; + static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = 0xC0000033; + static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = 0xC0000135; + static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = 0xC0000059; + static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = 0xC000A083; + static constexpr HRESULT WIL_E_FAIL = 0x80004005; + + NTSTATUS status = STATUS_SUCCESS; + + switch (hr) + { + case S_OK: + status = STATUS_SUCCESS; + break; + case E_INVALIDARG: + status = WIL_STATUS_INVALID_PARAMETER; + break; + case __HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR): + status = WIL_STATUS_INTERNAL_ERROR; + break; + case E_OUTOFMEMORY: + status = STATUS_NO_MEMORY; + break; + case __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW): + status = WIL_STATUS_INTEGER_OVERFLOW; + break; + case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND): + status = WIL_STATUS_OBJECT_PATH_NOT_FOUND; + break; + case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): + status = WIL_STATUS_OBJECT_NAME_NOT_FOUND; + break; + case __HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION): + status = WIL_STATUS_NOT_IMPLEMENTED; + break; + case __HRESULT_FROM_WIN32(ERROR_MORE_DATA): + status = WIL_STATUS_BUFFER_OVERFLOW; + break; + case __HRESULT_FROM_WIN32(ERROR_IMPLEMENTATION_LIMIT): + status = WIL_STATUS_IMPLEMENTATION_LIMIT; + break; + case __HRESULT_FROM_WIN32(ERROR_NO_MORE_MATCHES): + status = WIL_STATUS_NO_MORE_MATCHES; + break; + case __HRESULT_FROM_WIN32(ERROR_ILLEGAL_CHARACTER): + status = WIL_STATUS_ILLEGAL_CHARACTER; + break; + case __HRESULT_FROM_WIN32(ERROR_UNDEFINED_CHARACTER): + status = WIL_STATUS_UNDEFINED_CHARACTER; + break; + case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): + status = WIL_STATUS_BUFFER_TOO_SMALL; + break; + case __HRESULT_FROM_WIN32(ERROR_DISK_FULL): + status = WIL_STATUS_DISK_FULL; + break; + case __HRESULT_FROM_WIN32(ERROR_INVALID_NAME): + status = WIL_STATUS_OBJECT_NAME_INVALID; + break; + case __HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND): + status = WIL_STATUS_DLL_NOT_FOUND; + break; + case __HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION): + status = WIL_STATUS_REVISION_MISMATCH; + break; + case WIL_E_FAIL: + status = STATUS_UNSUCCESSFUL; + break; + case __HRESULT_FROM_WIN32(ERROR_XML_PARSE_ERROR): + status = WIL_STATUS_XML_PARSE_ERROR; + break; + case __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION): + status = STATUS_NONCONTINUABLE_EXCEPTION; + break; + default: + if ((hr & FACILITY_NT_BIT) != 0) + { + status = (hr & ~FACILITY_NT_BIT); + } + else if (HRESULT_FACILITY(hr) == FACILITY_WIN32) + { + status = __NTSTATUS_FROM_WIN32(HRESULT_CODE(hr)); + } + else if (HRESULT_FACILITY(hr) == FACILITY_SSPI) + { + status = ((NTSTATUS)(hr) <= 0 + ? ((NTSTATUS)(hr)) + : ((NTSTATUS)(((hr) & 0x0000FFFF) | (FACILITY_SSPI << 16) | ERROR_SEVERITY_ERROR))); + } + else + { + status = WIL_STATUS_INTERNAL_ERROR; + } + break; + } + return status; + } + + // The following set of functions all differ only based upon number of arguments. They are unified in their + // handling of data from each of the various error-handling types (fast fail, exceptions, etc.). + _Post_equals_last_error_ inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + __R_FN_UNREFERENCED; + auto err = ::GetLastError(); + if (SUCCEEDED_WIN32(err)) + { + // This function should only be called when GetLastError() is set to a FAILURE. + // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues: + // 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not + // actually + // set the last error (consult MSDN). + // 2) Your macro check against the error is not immediately after the API call. Pushing it later can + // result + // in another API call between the previous one and the check resetting the last error. + // 3) The API you're calling has a bug in it and does not accurately set the last error (there are a + // few + // examples here, such as SendMessageTimeout() that don't accurately set the last error). + // [MSFT internal] For these, please send mail to 'wildisc' when found and work-around with + // win32errorhelpers. + + WI_USAGE_ERROR_FORWARD( + "CALLER BUG: Macro usage error detected. GetLastError() does not have an error."); + return ERROR_ASSERTION_FAILURE; + } + return err; + } + + inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT + { + __R_FN_LOCALS_FULL_RA; + return GetLastErrorFail(__R_FN_CALL_FULL); + } + + _Translates_last_error_to_HRESULT_ inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL)); + } + + _Translates_last_error_to_HRESULT_ inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT + { + __R_FN_LOCALS_FULL_RA; + return GetLastErrorFailHr(__R_FN_CALL_FULL); + } + + inline void PrintLoggingMessage(_Out_writes_(cchDest) _Post_z_ PWSTR pszDest, + _Pre_satisfies_(cchDest > 0) size_t cchDest, + _In_opt_ _Printf_format_string_ PCSTR formatString, + _In_opt_ va_list argList) WI_NOEXCEPT + { + if (formatString == nullptr) + { + pszDest[0] = L'\0'; + } + else if (argList == nullptr) + { + StringCchPrintfW(pszDest, cchDest, L"%hs", formatString); } else { - status = WIL_STATUS_INTERNAL_ERROR; + wchar_t szFormatWide[2048]; + StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString); + StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList); } - break; } - return status; - } - - // The following set of functions all differ only based upon number of arguments. They are unified in their handling - // of data from each of the various error-handling types (fast fail, exceptions, etc.). - _Post_equals_last_error_ inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT - { - __R_FN_UNREFERENCED; - auto err = ::GetLastError(); - if (SUCCEEDED_WIN32(err)) - { - // This function should only be called when GetLastError() is set to a FAILURE. - // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues: - // 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually - // set the last error (consult MSDN). - // 2) Your macro check against the error is not immediately after the API call. Pushing it later can result - // in another API call between the previous one and the check resetting the last error. - // 3) The API you're calling has a bug in it and does not accurately set the last error (there are a few - // examples here, such as SendMessageTimeout() that don't accurately set the last error). - // [MSFT internal] For these, please send mail to 'wildisc' when found and work-around with win32errorhelpers. - - WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. GetLastError() does not have an error."); - return ERROR_ASSERTION_FAILURE; - } - return err; - } - - inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT - { - __R_FN_LOCALS_FULL_RA; - return GetLastErrorFail(__R_FN_CALL_FULL); - } - - _Translates_last_error_to_HRESULT_ - inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT - { - return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL)); - } - - _Translates_last_error_to_HRESULT_ - inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT - { - __R_FN_LOCALS_FULL_RA; - return GetLastErrorFailHr(__R_FN_CALL_FULL); - } - - inline void PrintLoggingMessage( - _Out_writes_(cchDest) _Post_z_ PWSTR pszDest, - _Pre_satisfies_(cchDest > 0) size_t cchDest, - _In_opt_ _Printf_format_string_ PCSTR formatString, - _In_opt_ va_list argList) WI_NOEXCEPT - { - if (formatString == nullptr) - { - pszDest[0] = L'\0'; - } - else if (argList == nullptr) - { - StringCchPrintfW(pszDest, cchDest, L"%hs", formatString); - } - else - { - wchar_t szFormatWide[2048]; - StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString); - StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList); - } - } #pragma warning(push) #pragma warning(disable : __WARNING_RETURNING_BAD_RESULT) - // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using - // Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled). + // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to + // reduce the friction associated with using Result.h and ResultException.h in a build that does not have + // WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled). - inline HRESULT WilStringLengthWorkerA( - _In_reads_or_z_(cchMax) PCNZCH psz, - _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax, - _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength) - { - HRESULT hr = S_OK; - size_t cchOriginalMax = cchMax; - while (cchMax && (*psz != '\0')) + inline HRESULT WilStringLengthWorkerA(_In_reads_or_z_(cchMax) PCNZCH psz, + _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax, + _Out_opt_ _Deref_out_range_(<, cchMax) + _Deref_out_range_(<=, _String_length_(psz)) size_t *pcchLength) { - psz++; - cchMax--; - } - if (cchMax == 0) - { - // the string is longer than cchMax - hr = STRSAFE_E_INVALID_PARAMETER; - } - if (pcchLength) - { - if (SUCCEEDED(hr)) + HRESULT hr = S_OK; + size_t cchOriginalMax = cchMax; + while (cchMax && (*psz != '\0')) { - *pcchLength = cchOriginalMax - cchMax; + psz++; + cchMax--; + } + if (cchMax == 0) + { + // the string is longer than cchMax + hr = STRSAFE_E_INVALID_PARAMETER; + } + if (pcchLength) + { + if (SUCCEEDED(hr)) + { + *pcchLength = cchOriginalMax - cchMax; + } + else + { + *pcchLength = 0; + } + } + return hr; + } + + _Must_inspect_result_ inline HRESULT StringCchLengthA(_In_reads_or_z_(cchMax) PCNZCH psz, + _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax, + _Out_opt_ _Deref_out_range_(<, cchMax) + _Deref_out_range_(<=, _String_length_(psz)) + size_t *pcchLength) + { + HRESULT hr = S_OK; + if ((psz == nullptr) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; } else + { + hr = WilStringLengthWorkerA(psz, cchMax, pcchLength); + } + if (FAILED(hr) && pcchLength) { *pcchLength = 0; } + return hr; } - return hr; - } - - _Must_inspect_result_ - inline HRESULT StringCchLengthA( - _In_reads_or_z_(cchMax) PCNZCH psz, - _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax, - _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength) - { - HRESULT hr = S_OK; - if ((psz == nullptr) || (cchMax > STRSAFE_MAX_CCH)) - { - hr = STRSAFE_E_INVALID_PARAMETER; - } - else - { - hr = WilStringLengthWorkerA(psz, cchMax, pcchLength); - } - if (FAILED(hr) && pcchLength) - { - *pcchLength = 0; - } - return hr; - } #pragma warning(pop) - _Post_satisfies_(cchDest > 0 && cchDest <= cchMax) inline HRESULT - WilStringValidateDestA(_In_reads_opt_(cchDest) PCNZCH /*pszDest*/, _In_ size_t cchDest, _In_ const size_t cchMax) - { - HRESULT hr = S_OK; - if ((cchDest == 0) || (cchDest > cchMax)) + _Post_satisfies_(cchDest > 0 && cchDest <= cchMax) inline HRESULT + WilStringValidateDestA(_In_reads_opt_(cchDest) PCNZCH /*pszDest*/, _In_ size_t cchDest, + _In_ const size_t cchMax) { - hr = STRSAFE_E_INVALID_PARAMETER; + HRESULT hr = S_OK; + if ((cchDest == 0) || (cchDest > cchMax)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + return hr; } - return hr; - } - inline HRESULT WilStringVPrintfWorkerA( - _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, - _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest, - _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength, - _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, - _In_ va_list argList) - { - HRESULT hr = S_OK; - int iRet{}; + inline HRESULT WilStringVPrintfWorkerA(_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, + _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest, + _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) + size_t *pcchNewDestLength, + _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, + _In_ va_list argList) + { + HRESULT hr = S_OK; + int iRet{}; - // leave the last space for the null terminator - size_t cchMax = cchDest - 1; - size_t cchNewDestLength = 0; + // leave the last space for the null terminator + size_t cchMax = cchDest - 1; + size_t cchNewDestLength = 0; #undef STRSAFE_USE_SECURE_CRT #define STRSAFE_USE_SECURE_CRT 1 #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL) - iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList); + iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList); #else #pragma warning(push) #pragma warning(disable : __WARNING_BANNED_API_USAGE) // "STRSAFE not included" - iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); + iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); #pragma warning(pop) #endif - // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); - if ((iRet < 0) || (((size_t)iRet) > cchMax)) - { - // need to null terminate the string - pszDest += cchMax; - *pszDest = '\0'; + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; - cchNewDestLength = cchMax; + cchNewDestLength = cchMax; - // we have truncated pszDest - hr = STRSAFE_E_INSUFFICIENT_BUFFER; - } - else if (((size_t)iRet) == cchMax) - { - // need to null terminate the string - pszDest += cchMax; - *pszDest = '\0'; + // we have truncated pszDest + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; - cchNewDestLength = cchMax; - } - else - { - cchNewDestLength = (size_t)iRet; + cchNewDestLength = cchMax; + } + else + { + cchNewDestLength = (size_t)iRet; + } + + if (pcchNewDestLength) + { + *pcchNewDestLength = cchNewDestLength; + } + + return hr; } - if (pcchNewDestLength) + inline HRESULT StringCchPrintfA(_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, + _In_ size_t cchDest, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, ...) { - *pcchNewDestLength = cchNewDestLength; + HRESULT hr; + hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH); + if (SUCCEEDED(hr)) + { + va_list argList; + va_start(argList, pszFormat); + hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, nullptr, pszFormat, argList); + va_end(argList); + } + else if (cchDest > 0) + { + *pszDest = '\0'; + } + return hr; } - return hr; - } - - inline HRESULT StringCchPrintfA( - _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, - _In_ size_t cchDest, - _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, - ...) - { - HRESULT hr; - hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH); - if (SUCCEEDED(hr)) + _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char))) inline size_t + ResultStringSize(_In_opt_ PCSTR psz) { - va_list argList; - va_start(argList, pszFormat); - hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, nullptr, pszFormat, argList); - va_end(argList); - } - else if (cchDest > 0) - { - *pszDest = '\0'; - } - return hr; - } - - _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char))) - inline size_t ResultStringSize(_In_opt_ PCSTR psz) - { - return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); - } - - _Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t))) - inline size_t ResultStringSize(_In_opt_ PCWSTR psz) - { - return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); - } - - template - _Ret_range_(pStart, pEnd) - inline unsigned char* WriteResultString( - _Pre_satisfies_(pStart <= pEnd) _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_) _When_( - (pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0), - _Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) unsigned char* pStart, - _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, - _In_opt_z_ TString pszString, - _Outptr_result_maybenull_z_ TString* ppszBufferString) - { - // No space? Null string? Do nothing. - if ((pStart == pEnd) || !pszString || !*pszString) - { - assign_null_to_opt_param(ppszBufferString); - return pStart; + return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); } - // Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to - // the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough, - // do nothing, and tell the caller nothing was written. - size_t const stringSize = ResultStringSize(pszString); - size_t const bufferSize = pEnd - pStart; - if (bufferSize < stringSize) + _Ret_range_(sizeof(wchar_t), + (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t))) inline size_t + ResultStringSize(_In_opt_ PCWSTR psz) { - assign_null_to_opt_param(ppszBufferString); - return pStart; + return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); } - memcpy_s(pStart, bufferSize, pszString, stringSize); - assign_to_opt_param( - ppszBufferString, - reinterpret_cast( - pStart)); // lgtm[cpp/incorrect-string-type-conversion] False positive - The query is misinterpreting a buffer (char *) with a MBS string, the cast to TString is expected. - return pStart + stringSize; - } + template + _Ret_range_(pStart, pEnd) inline unsigned char *WriteResultString( + _Pre_satisfies_(pStart <= pEnd) _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), + _In_opt_) + _When_((pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0), + _Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) unsigned char *pStart, + _Pre_satisfies_(pEnd >= pStart) unsigned char *pEnd, _In_opt_z_ TString pszString, + _Outptr_result_maybenull_z_ TString *ppszBufferString) + { + // No space? Null string? Do nothing. + if ((pStart == pEnd) || !pszString || !*pszString) + { + assign_null_to_opt_param(ppszBufferString); + return pStart; + } - _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) - inline size_t UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax) - { - size_t cbLength; - return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0; - } - _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) - inline size_t UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax) - { - size_t cbLength; - return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0; - } + // Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to + // the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough, + // do nothing, and tell the caller nothing was written. + size_t const stringSize = ResultStringSize(pszString); + size_t const bufferSize = pEnd - pStart; + if (bufferSize < stringSize) + { + assign_null_to_opt_param(ppszBufferString); + return pStart; + } - template - _Ret_range_(pStart, pEnd) - inline unsigned char* GetResultString( - _In_reads_to_ptr_opt_(pEnd) unsigned char* pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, _Out_ TString* ppszBufferString) - { - size_t cchLen = UntrustedStringLength(reinterpret_cast(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0])); - *ppszBufferString = (cchLen > 0) ? reinterpret_cast(pStart) : nullptr; - auto pReturn = (wistd::min)(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0]))); - __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd)); - return pReturn; - } -} // namespace details -/// @endcond + memcpy_s(pStart, bufferSize, pszString, stringSize); + assign_to_opt_param( + ppszBufferString, + reinterpret_cast( + pStart)); // lgtm[cpp/incorrect-string-type-conversion] False positive - The query is + // misinterpreting a buffer (char *) with a MBS string, the cast to TString is expected. + return pStart + stringSize; + } -//***************************************************************************** -// WIL result handling initializers -// -// Generally, callers do not need to manually initialize WIL. This header creates -// the appropriate .CRT init section pieces through global objects to ensure that -// WilInitialize... is called before DllMain or main(). -// -// Certain binaries do not link with the CRT or do not support .CRT-section based -// initializers. Those binaries must link only with other static libraries that -// also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left, -// and they should call one of the WilInitialize_ResultMacros_??? methods during -// their initialization phase. Skipping this initialization path is OK as well, -// but results in a slightly degraded experience with result reporting. -// -// Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides: -// - The name of the current module in wil::FailureInfo::pszModule -// - The name of the returning-to module during wil/staging.h failures -//***************************************************************************** + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t + UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax) + { + size_t cbLength; + return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0; + } + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t + UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax) + { + size_t cbLength; + return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0; + } + + template + _Ret_range_(pStart, + pEnd) inline unsigned char *GetResultString(_In_reads_to_ptr_opt_(pEnd) unsigned char *pStart, + _Pre_satisfies_(pEnd >= pStart) unsigned char *pEnd, + _Out_ TString *ppszBufferString) + { + size_t cchLen = UntrustedStringLength(reinterpret_cast(pStart), + (pEnd - pStart) / sizeof((*ppszBufferString)[0])); + *ppszBufferString = (cchLen > 0) ? reinterpret_cast(pStart) : nullptr; + auto pReturn = (wistd::min)(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0]))); + __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd)); + return pReturn; + } + } // namespace details + /// @endcond + + //***************************************************************************** + // WIL result handling initializers + // + // Generally, callers do not need to manually initialize WIL. This header creates + // the appropriate .CRT init section pieces through global objects to ensure that + // WilInitialize... is called before DllMain or main(). + // + // Certain binaries do not link with the CRT or do not support .CRT-section based + // initializers. Those binaries must link only with other static libraries that + // also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left, + // and they should call one of the WilInitialize_ResultMacros_??? methods during + // their initialization phase. Skipping this initialization path is OK as well, + // but results in a slightly degraded experience with result reporting. + // + // Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides: + // - The name of the current module in wil::FailureInfo::pszModule + // - The name of the returning-to module during wil/staging.h failures + //***************************************************************************** #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -//! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. WIL will -//! only use publicly documented APIs. -inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse() -{ - details::g_pfnGetModuleName = details::GetCurrentModuleName; - details::g_pfnGetModuleInformation = details::GetModuleInformation; - details::g_pfnDebugBreak = details::DebugBreak; - details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException; -} + //! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. + //! WIL will only use publicly documented APIs. + inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse() + { + details::g_pfnGetModuleName = details::GetCurrentModuleName; + details::g_pfnGetModuleInformation = details::GetModuleInformation; + details::g_pfnDebugBreak = details::DebugBreak; + details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException; + } -/// @cond -namespace details -{ + /// @cond + namespace details + { #ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS #if !defined(BUILD_WINDOWS) || defined(WIL_SUPPRESS_PRIVATE_API_USE) - WI_HEADER_INITIALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, [] { - ::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse(); - return 1; - }); + WI_HEADER_INITIALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, [] { + ::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse(); + return 1; + }); #endif #endif -} // namespace details + } // namespace details /// @endcond #else // !WINAPI_PARTITION_DESKTOP, !WINAPI_PARTITION_SYSTEM, explicitly assume these modules can direct link -namespace details -{ - WI_HEADER_INITIALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, [] { - g_pfnRaiseFailFastException = ::RaiseFailFastException; - return 1; - }); -} // namespace details + namespace details + { + WI_HEADER_INITIALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, [] { + g_pfnRaiseFailFastException = ::RaiseFailFastException; + return 1; + }); + } // namespace details #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -//***************************************************************************** -// Public Error Handling Helpers -//***************************************************************************** + //***************************************************************************** + // Public Error Handling Helpers + //***************************************************************************** -//! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload). -inline bool ProcessShutdownInProgress() -{ - return (details::g_processShutdownInProgress || (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false)); -} - -/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down, -but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll). The hosting DLL is responsible for calling -Construct() and Destroy() to manually run the constructor and destructor during DLL load & unload. -Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is -called as is typical. */ -template -class manually_managed_shutdown_aware_object -{ -public: - manually_managed_shutdown_aware_object() = default; - manually_managed_shutdown_aware_object(manually_managed_shutdown_aware_object const&) = delete; - void operator=(manually_managed_shutdown_aware_object const&) = delete; - - void construct() + //! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload). + inline bool ProcessShutdownInProgress() { - void* var = &m_raw; - ::new (var) T(); + return (details::g_processShutdownInProgress || + (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false)); } - void destroy() + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is + shutting down, but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll). The hosting DLL is + responsible for calling Construct() and Destroy() to manually run the constructor and destructor during DLL load & + unload. Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, + otherwise the destructor is called as is typical. */ + template class manually_managed_shutdown_aware_object { - if (ProcessShutdownInProgress()) + public: + manually_managed_shutdown_aware_object() = default; + manually_managed_shutdown_aware_object(manually_managed_shutdown_aware_object const &) = delete; + void operator=(manually_managed_shutdown_aware_object const &) = delete; + + void construct() { - get().ProcessShutdown(); + void *var = &m_raw; + ::new (var) T(); } - else + + void destroy() { - (&get())->~T(); + if (ProcessShutdownInProgress()) + { + get().ProcessShutdown(); + } + else + { + (&get())->~T(); + } + } + + //! Retrieves a reference to the contained object + T &get() WI_NOEXCEPT + { + return *reinterpret_cast(&m_raw); + } + + private: + alignas(T) unsigned char m_raw[sizeof(T)]; + }; + + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is + shutting down. Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, + otherwise the destructor is called as is typical. */ + template class shutdown_aware_object + { + public: + shutdown_aware_object() + { + m_object.construct(); + } + + ~shutdown_aware_object() + { + m_object.destroy(); + } + + shutdown_aware_object(shutdown_aware_object const &) = delete; + void operator=(shutdown_aware_object const &) = delete; + + //! Retrieves a reference to the contained object + T &get() WI_NOEXCEPT + { + return m_object.get(); + } + + private: + manually_managed_shutdown_aware_object m_object; + }; + + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is + * shutting down. */ + template class object_without_destructor_on_shutdown + { + public: + object_without_destructor_on_shutdown() + { + void *var = &m_raw; + ::new (var) T(); + } + + ~object_without_destructor_on_shutdown() + { + if (!ProcessShutdownInProgress()) + { + get().~T(); + } + } + + object_without_destructor_on_shutdown(object_without_destructor_on_shutdown const &) = delete; + void operator=(object_without_destructor_on_shutdown const &) = delete; + + //! Retrieves a reference to the contained object + T &get() WI_NOEXCEPT + { + return *reinterpret_cast(&m_raw); + } + + private: + alignas(T) unsigned char m_raw[sizeof(T)]{}; + }; + + /** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because + of termination or normal unload. Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this + determination on its own without this callback. Suppressing private APIs requires use of this. */ + inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved) + { + if (!details::g_processShutdownInProgress) + { + if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr)) + { + details::g_processShutdownInProgress = true; + } } } - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT + // [optionally] Plug in fallback telemetry reporting + // Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module + // could re-route fallback telemetry to any ONE specific provider by calling this method. + inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction) { - return *reinterpret_cast(&m_raw); + // Only ONE telemetry provider can own the fallback telemetry callback. + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) || + (details::g_pfnTelemetryCallback == callbackFunction)); + details::g_pfnTelemetryCallback = callbackFunction; } -private: - alignas(T) unsigned char m_raw[sizeof(T)]; -}; - -/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. -Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is -called as is typical. */ -template -class shutdown_aware_object -{ -public: - shutdown_aware_object() + // [optionally] Plug in result logging (do not use for telemetry) + // This provides the ability for a module to hook all failures flowing through the system for inspection + // and/or logging. + inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction) { - m_object.construct(); + // Only ONE function can own the result logging callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) || + (details::g_pfnLoggingCallback == callbackFunction)); + details::g_pfnLoggingCallback = callbackFunction; } - ~shutdown_aware_object() + // [optionally] Plug in custom result messages + // There are some purposes that require translating the full information that is known about a failure + // into a message to be logged (either through the console for debugging OR as the message attached + // to a Platform::Exception^). This callback allows a module to format the string itself away from the + // default. + inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction) { - m_object.destroy(); + // Only ONE function can own the result message callback + __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || + (g_pfnResultLoggingCallback == callbackFunction)); + details::g_resultMessageCallbackSet = true; + g_pfnResultLoggingCallback = callbackFunction; } - shutdown_aware_object(shutdown_aware_object const&) = delete; - void operator=(shutdown_aware_object const&) = delete; - - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT + // [optionally] Plug in exception remapping + // A module can plug a callback in using this function to setup custom exception handling to allow any + // exception type to be converted into an HRESULT from exception barriers. + inline void SetResultFromCaughtExceptionCallback( + _In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction) { - return m_object.get(); + // Only ONE function can own the exception conversion + __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) || + (g_pfnResultFromCaughtException == callbackFunction)); + g_pfnResultFromCaughtException = callbackFunction; } -private: - manually_managed_shutdown_aware_object m_object; -}; - -/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. */ -template -class object_without_destructor_on_shutdown -{ -public: - object_without_destructor_on_shutdown() + // [optionally] Plug in exception remapping + // This provides the ability for a module to call RoOriginateError in case of a failure. + // Normally, the callback is owned by including result_originate.h in the including module. Alternatively a module + // could re-route error origination callback to its own implementation. + inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction) { - void* var = &m_raw; - ::new (var) T(); + // Only ONE function can own the error origination callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) || + (details::g_pfnOriginateCallback == callbackFunction)); + details::g_pfnOriginateCallback = callbackFunction; } - ~object_without_destructor_on_shutdown() + // [optionally] Plug in failfast callback + // This provides the ability for a module to call RoFailFastWithErrorContext in the failfast handler -if- there is + // stowed exception data available. Normally, the callback is owned by including result_originate.h in the + // including module. Alternatively a module could re-route to its own implementation. + inline void SetFailfastWithContextCallback( + _In_opt_ decltype(details::g_pfnFailfastWithContextCallback) callbackFunction) { - if (!ProcessShutdownInProgress()) + // Only ONE function can own the failfast with context callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnFailfastWithContextCallback == nullptr) || + (callbackFunction == nullptr) || + (details::g_pfnFailfastWithContextCallback == callbackFunction)); + details::g_pfnFailfastWithContextCallback = callbackFunction; + } + + // A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed + // on the stack or from the caller). The storage of FailureInfo needs to copy some data internally + // for lifetime purposes. + + class StoredFailureInfo + { + public: + StoredFailureInfo() WI_NOEXCEPT { - get().~T(); - } - } - - object_without_destructor_on_shutdown(object_without_destructor_on_shutdown const&) = delete; - void operator=(object_without_destructor_on_shutdown const&) = delete; - - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT - { - return *reinterpret_cast(&m_raw); - } - -private: - alignas(T) unsigned char m_raw[sizeof(T)]{}; -}; - -/** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because -of termination or normal unload. Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this -determination on its own without this callback. Suppressing private APIs requires use of this. */ -inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved) -{ - if (!details::g_processShutdownInProgress) - { - if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr)) - { - details::g_processShutdownInProgress = true; - } - } -} - -// [optionally] Plug in fallback telemetry reporting -// Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module -// could re-route fallback telemetry to any ONE specific provider by calling this method. -inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction) -{ - // Only ONE telemetry provider can own the fallback telemetry callback. - __FAIL_FAST_IMMEDIATE_ASSERT__( - (details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) || - (details::g_pfnTelemetryCallback == callbackFunction)); - details::g_pfnTelemetryCallback = callbackFunction; -} - -// [optionally] Plug in result logging (do not use for telemetry) -// This provides the ability for a module to hook all failures flowing through the system for inspection -// and/or logging. -inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction) -{ - // Only ONE function can own the result logging callback - __FAIL_FAST_IMMEDIATE_ASSERT__( - (details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) || - (details::g_pfnLoggingCallback == callbackFunction)); - details::g_pfnLoggingCallback = callbackFunction; -} - -// [optionally] Plug in custom result messages -// There are some purposes that require translating the full information that is known about a failure -// into a message to be logged (either through the console for debugging OR as the message attached -// to a Platform::Exception^). This callback allows a module to format the string itself away from the -// default. -inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction) -{ - // Only ONE function can own the result message callback - __FAIL_FAST_IMMEDIATE_ASSERT__( - (g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || (g_pfnResultLoggingCallback == callbackFunction)); - details::g_resultMessageCallbackSet = true; - g_pfnResultLoggingCallback = callbackFunction; -} - -// [optionally] Plug in exception remapping -// A module can plug a callback in using this function to setup custom exception handling to allow any -// exception type to be converted into an HRESULT from exception barriers. -inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction) -{ - // Only ONE function can own the exception conversion - __FAIL_FAST_IMMEDIATE_ASSERT__( - (g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) || - (g_pfnResultFromCaughtException == callbackFunction)); - g_pfnResultFromCaughtException = callbackFunction; -} - -// [optionally] Plug in exception remapping -// This provides the ability for a module to call RoOriginateError in case of a failure. -// Normally, the callback is owned by including result_originate.h in the including module. Alternatively a module -// could re-route error origination callback to its own implementation. -inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction) -{ - // Only ONE function can own the error origination callback - __FAIL_FAST_IMMEDIATE_ASSERT__( - (details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) || - (details::g_pfnOriginateCallback == callbackFunction)); - details::g_pfnOriginateCallback = callbackFunction; -} - -// [optionally] Plug in failfast callback -// This provides the ability for a module to call RoFailFastWithErrorContext in the failfast handler -if- there is stowed -// exception data available. Normally, the callback is owned by including result_originate.h in the including module. -// Alternatively a module could re-route to its own implementation. -inline void SetFailfastWithContextCallback(_In_opt_ decltype(details::g_pfnFailfastWithContextCallback) callbackFunction) -{ - // Only ONE function can own the failfast with context callback - __FAIL_FAST_IMMEDIATE_ASSERT__( - (details::g_pfnFailfastWithContextCallback == nullptr) || (callbackFunction == nullptr) || - (details::g_pfnFailfastWithContextCallback == callbackFunction)); - details::g_pfnFailfastWithContextCallback = callbackFunction; -} - -// A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed -// on the stack or from the caller). The storage of FailureInfo needs to copy some data internally -// for lifetime purposes. - -class StoredFailureInfo -{ -public: - StoredFailureInfo() WI_NOEXCEPT - { - ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo)); - } - - StoredFailureInfo(FailureInfo const& other) WI_NOEXCEPT - { - SetFailureInfo(other); - } - - WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT - { - return m_failureInfo; - } - - void SetFailureInfo(FailureInfo const& failure) WI_NOEXCEPT - { - m_failureInfo = failure; - - size_t const cbNeed = details::ResultStringSize(failure.pszMessage) + details::ResultStringSize(failure.pszCode) + - details::ResultStringSize(failure.pszFunction) + details::ResultStringSize(failure.pszFile) + - details::ResultStringSize(failure.pszCallContext) + details::ResultStringSize(failure.pszModule) + - details::ResultStringSize(failure.callContextCurrent.contextName) + - details::ResultStringSize(failure.callContextCurrent.contextMessage) + - details::ResultStringSize(failure.callContextOriginating.contextName) + - details::ResultStringSize(failure.callContextOriginating.contextMessage); - - if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed)) - { - m_spStrings.reset(); - m_spStrings.create(cbNeed); + ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo)); } - size_t cbAlloc; - unsigned char* pBuffer = static_cast(m_spStrings.get(&cbAlloc)); - unsigned char* pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr; - - if (pBuffer) + StoredFailureInfo(FailureInfo const &other) WI_NOEXCEPT { - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule); - pBuffer = details::WriteResultString( - pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName); - pBuffer = details::WriteResultString( - pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage); - pBuffer = details::WriteResultString( - pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName); - pBuffer = details::WriteResultString( - pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage); - ZeroMemory(pBuffer, pBufferEnd - pBuffer); + SetFailureInfo(other); } - } - // Relies upon generated copy constructor and assignment operator + WI_NODISCARD FailureInfo const &GetFailureInfo() const WI_NOEXCEPT + { + return m_failureInfo; + } -protected: - FailureInfo m_failureInfo; - details::shared_buffer m_spStrings; -}; + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failureInfo = failure; + + size_t const cbNeed = + details::ResultStringSize(failure.pszMessage) + details::ResultStringSize(failure.pszCode) + + details::ResultStringSize(failure.pszFunction) + details::ResultStringSize(failure.pszFile) + + details::ResultStringSize(failure.pszCallContext) + details::ResultStringSize(failure.pszModule) + + details::ResultStringSize(failure.callContextCurrent.contextName) + + details::ResultStringSize(failure.callContextCurrent.contextMessage) + + details::ResultStringSize(failure.callContextOriginating.contextName) + + details::ResultStringSize(failure.callContextOriginating.contextMessage); + + if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed)) + { + m_spStrings.reset(); + m_spStrings.create(cbNeed); + } + + size_t cbAlloc; + unsigned char *pBuffer = static_cast(m_spStrings.get(&cbAlloc)); + unsigned char *pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr; + + if (pBuffer) + { + pBuffer = + details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode); + pBuffer = + details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, + &m_failureInfo.pszCallContext); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextName, + &m_failureInfo.callContextCurrent.contextName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, + &m_failureInfo.callContextCurrent.contextMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextName, + &m_failureInfo.callContextOriginating.contextName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, + &m_failureInfo.callContextOriginating.contextMessage); + ZeroMemory(pBuffer, pBufferEnd - pBuffer); + } + } + + // Relies upon generated copy constructor and assignment operator + + protected: + FailureInfo m_failureInfo; + details::shared_buffer m_spStrings; + }; #if defined(WIL_ENABLE_EXCEPTIONS) || defined(WIL_FORCE_INCLUDE_RESULT_EXCEPTION) -//! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx). -//! This class stores all of the FailureInfo context that is available when the exception is thrown. It's also caught by -//! exception guards for automatic conversion to HRESULT. -//! -//! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException has been -//! changed). -class ResultException : public std::exception -{ -public: - //! Constructs a new ResultException from an existing FailureInfo. - ResultException(const FailureInfo& failure) WI_NOEXCEPT : m_failure(failure) + //! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx). + //! This class stores all of the FailureInfo context that is available when the exception is thrown. It's also + //! caught by exception guards for automatic conversion to HRESULT. + //! + //! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException + //! has been changed). + class ResultException : public std::exception { - } + public: + //! Constructs a new ResultException from an existing FailureInfo. + ResultException(const FailureInfo &failure) WI_NOEXCEPT : m_failure(failure) + { + } - //! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types). - ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : m_failure(CustomExceptionFailureInfo(hr)) - { - } + //! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types). + ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : m_failure(CustomExceptionFailureInfo(hr)) + { + } - //! Returns the failed HRESULT that this exception represents. - WI_NODISCARD _Always_(_Post_satisfies_(return < 0)) HRESULT GetErrorCode() const WI_NOEXCEPT - { - HRESULT const hr = m_failure.GetFailureInfo().hr; - __analysis_assume(hr < 0); - return hr; - } + //! Returns the failed HRESULT that this exception represents. + WI_NODISCARD _Always_(_Post_satisfies_(return < 0)) HRESULT GetErrorCode() const WI_NOEXCEPT + { + HRESULT const hr = m_failure.GetFailureInfo().hr; + __analysis_assume(hr < 0); + return hr; + } - //! Returns the failed NTSTATUS that this exception represents. - WI_NODISCARD _Always_(_Post_satisfies_(return < 0)) NTSTATUS GetStatusCode() const WI_NOEXCEPT - { - NTSTATUS const status = m_failure.GetFailureInfo().status; - __analysis_assume(status < 0); - return status; - } + //! Returns the failed NTSTATUS that this exception represents. + WI_NODISCARD _Always_(_Post_satisfies_(return < 0)) NTSTATUS GetStatusCode() const WI_NOEXCEPT + { + NTSTATUS const status = m_failure.GetFailureInfo().status; + __analysis_assume(status < 0); + return status; + } - //! Get a reference to the stored FailureInfo. - WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT - { - return m_failure.GetFailureInfo(); - } + //! Get a reference to the stored FailureInfo. + WI_NODISCARD FailureInfo const &GetFailureInfo() const WI_NOEXCEPT + { + return m_failure.GetFailureInfo(); + } - //! Sets the stored FailureInfo (use primarily only when constructing custom exception types). - void SetFailureInfo(FailureInfo const& failure) WI_NOEXCEPT - { - m_failure.SetFailureInfo(failure); - } + //! Sets the stored FailureInfo (use primarily only when constructing custom exception types). + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failure.SetFailureInfo(failure); + } - //! Provides a string representing the FailureInfo from this exception. - WI_NODISCARD inline const char* __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override - { + //! Provides a string representing the FailureInfo from this exception. + WI_NODISCARD inline const char *__CLR_OR_THIS_CALL what() const WI_NOEXCEPT override + { #if !defined(NONLS) && !defined(NOAPISET) - if (!m_what) - { - wchar_t message[2048]; - GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); - - int len = WideCharToMultiByte(CP_ACP, 0, message, -1, nullptr, 0, nullptr, nullptr); - if (!m_what.create(len)) + if (!m_what) { - // Allocation failed, return placeholder string. - return "WIL Exception"; + wchar_t message[2048]; + GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); + + int len = WideCharToMultiByte(CP_ACP, 0, message, -1, nullptr, 0, nullptr, nullptr); + if (!m_what.create(len)) + { + // Allocation failed, return placeholder string. + return "WIL Exception"; + } + + WideCharToMultiByte(CP_ACP, 0, message, -1, static_cast(m_what.get()), len, nullptr, nullptr); } - - WideCharToMultiByte(CP_ACP, 0, message, -1, static_cast(m_what.get()), len, nullptr, nullptr); - } - return static_cast(m_what.get()); + return static_cast(m_what.get()); #else - if (!m_what) - { - wchar_t message[2048]; - GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); + if (!m_what) + { + wchar_t message[2048]; + GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); - char messageA[1024]; - wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message); - m_what.create(messageA, strlen(messageA) + sizeof(*messageA)); + char messageA[1024]; + wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message); + m_what.create(messageA, strlen(messageA) + sizeof(*messageA)); + } + return static_cast(m_what.get()); +#endif } - return static_cast(m_what.get()); -#endif - } - // Relies upon auto-generated copy constructor and assignment operator -protected: - StoredFailureInfo m_failure; //!< The failure information for this exception - mutable details::shared_buffer m_what; //!< The on-demand generated what() string + // Relies upon auto-generated copy constructor and assignment operator + protected: + StoredFailureInfo m_failure; //!< The failure information for this exception + mutable details::shared_buffer m_what; //!< The on-demand generated what() string - //! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types). - static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT - { - FailureInfo fi = {}; - fi.type = FailureType::Exception; - fi.hr = hr; - return fi; - } -}; + //! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types). + static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT + { + FailureInfo fi = {}; + fi.type = FailureType::Exception; + fi.hr = hr; + return fi; + } + }; #endif -//***************************************************************************** -// Public Helpers that catch -- mostly only enabled when exceptions are enabled -//***************************************************************************** + //***************************************************************************** + // Public Helpers that catch -- mostly only enabled when exceptions are enabled + //***************************************************************************** -// ResultFromCaughtException 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 HRESULT. If an exception is of an unrecognized type -// the function will fail fast. -// -// try -// { -// // Code -// } -// catch (...) -// { -// hr = wil::ResultFromCaughtException(); -// } -_Always_(_Post_satisfies_(return < 0)) __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT -{ - bool isNormalized = false; - HRESULT hr = S_OK; - if (details::g_pfnResultFromCaughtExceptionInternal) + // ResultFromCaughtException 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 HRESULT. If an exception is of an unrecognized type + // the function will fail fast. + // + // try + // { + // // Code + // } + // catch (...) + // { + // hr = wil::ResultFromCaughtException(); + // } + _Always_(_Post_satisfies_(return < 0)) __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT { - hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).hr; - } - if (FAILED(hr)) - { - return hr; + bool isNormalized = false; + HRESULT hr = S_OK; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).hr; + } + if (FAILED(hr)) + { + return hr; + } + + // Caller bug: an unknown exception was thrown + __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), + g_fResultFailFastUnknownExceptions); + return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); } - // Caller bug: an unknown exception was thrown - __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions); - return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); -} - -//! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running under an -//! exception context -inline void RethrowCaughtException() -{ - // We always want to rethrow the exception under normal circumstances. Ordinarily, we could actually guarantee - // this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running - // dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the - // runtime check without the noreturn annotation. - - if (details::g_pfnRethrow) + //! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running + //! under an exception context + inline void RethrowCaughtException() { - details::g_pfnRethrow(); - } -} + // We always want to rethrow the exception under normal circumstances. Ordinarily, we could actually guarantee + // this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running + // dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the + // runtime check without the noreturn annotation. -//! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code -inline void ThrowResultException(const FailureInfo& failure) -{ - if (details::g_pfnThrowResultException) + if (details::g_pfnRethrow) + { + details::g_pfnRethrow(); + } + } + + //! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code + inline void ThrowResultException(const FailureInfo &failure) { - details::g_pfnThrowResultException(failure); + if (details::g_pfnThrowResultException) + { + details::g_pfnThrowResultException(failure); + } } -} -/// @cond -namespace details -{ + /// @cond + namespace details + { #ifdef WIL_ENABLE_EXCEPTIONS - //***************************************************************************** - // Private helpers to catch and propagate exceptions - //***************************************************************************** + //***************************************************************************** + // Private helpers to catch and propagate exceptions + //***************************************************************************** - RESULT_NORETURN inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS) - { - // This is an intentional fail-fast that was caught by an exception guard with WIL. Look back up the callstack to - // determine the source of the actual exception being thrown. The exception guard used by the calling code did not expect - // this exception type to be thrown or is specifically requesting fail-fast for this class of exception. - - FailureInfo failure{}; - WilFailFast(failure); - } - - inline void MaybeGetExceptionString( - const ResultException& exception, - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) + RESULT_NORETURN inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS) { - GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo()); - } - } + // This is an intentional fail-fast that was caught by an exception guard with WIL. Look back up the + // callstack to determine the source of the actual exception being thrown. The exception guard used by the + // calling code did not expect this exception type to be thrown or is specifically requesting fail-fast for + // this class of exception. - inline void MaybeGetExceptionString( - const std::exception& exception, - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) + FailureInfo failure{}; + WilFailFast(failure); + } + + inline void MaybeGetExceptionString(const ResultException &exception, + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) + size_t debugStringChars) { - StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what()); + if (debugString) + { + GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo()); + } } - } - inline HRESULT ResultFromKnownException(const ResultException& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - auto hr = exception.GetErrorCode(); - wil::details::ReportFailure_Base( - __R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } + inline void MaybeGetExceptionString(const std::exception &exception, + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) + size_t debugStringChars) + { + if (debugString) + { + StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what()); + } + } - inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - constexpr auto hr = E_OUTOFMEMORY; - wil::details::ReportFailure_Base( - __R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress) - { - if (g_pfnResultFromCaughtException_CppWinRt) + inline HRESULT ResultFromKnownException(const ResultException &exception, const DiagnosticsInfo &diagnostics, + void *returnAddress) { wchar_t message[2048]{}; - bool ignored; - auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored); - if (FAILED(hr)) - { - ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + auto hr = exception.GetErrorCode(); + wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), + ResultStatus::FromResult(hr), message); + return hr; } - // Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success - return S_OK; - } - - inline HRESULT RecognizeCaughtExceptionFromCallback( - _Inout_updates_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - HRESULT hr = g_pfnResultFromCaughtException(); - - // If we still don't know the error -- or we would like to get the debug string for the error (if possible) we - // rethrow and catch std::exception. - - if (SUCCEEDED(hr) || debugString) + inline HRESULT ResultFromKnownException(const std::bad_alloc &exception, const DiagnosticsInfo &diagnostics, + void *returnAddress) { - try + wchar_t message[2048]{}; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + constexpr auto hr = E_OUTOFMEMORY; + wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), + ResultStatus::FromResult(hr), message); + return hr; + } + + inline HRESULT ResultFromKnownException(const std::exception &exception, const DiagnosticsInfo &diagnostics, + void *returnAddress) + { + wchar_t message[2048]{}; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), + ResultStatus::FromResult(hr), message); + return hr; + } + + inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo &diagnostics, void *returnAddress) + { + if (g_pfnResultFromCaughtException_CppWinRt) { - throw; - } - catch (std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - if (SUCCEEDED(hr)) + wchar_t message[2048]{}; + bool ignored; + auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored); + if (FAILED(hr)) { - hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), + ResultStatus::FromResult(hr), message); + return hr; } } - catch (...) - { - // Fall through to returning 'hr' below - } + + // Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success + return S_OK; } - return hr; - } + inline HRESULT RecognizeCaughtExceptionFromCallback(_Inout_updates_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, + _Pre_satisfies_(debugStringChars > 0)) + size_t debugStringChars) + { + HRESULT hr = g_pfnResultFromCaughtException(); - // clang-format off + // If we still don't know the error -- or we would like to get the debug string for the error (if possible) + // we rethrow and catch std::exception. + + if (SUCCEEDED(hr) || debugString) + { + try + { + throw; + } + catch (std::exception &exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + if (SUCCEEDED(hr)) + { + hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + } + catch (...) + { + // Fall through to returning 'hr' below + } + } + + return hr; + } + + // clang-format off #ifdef __cplusplus_winrt inline Platform::String^ GetPlatformExceptionMessage(Platform::Exception^ exception) { @@ -3919,1276 +3966,1299 @@ namespace details }); #endif #endif - // clang-format on + // clang-format on - inline void __stdcall Rethrow() - { - throw; - } - - inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure) - { - throw ResultException(failure); - } - - __declspec(noinline) inline ResultStatus __stdcall ResultFromCaughtExceptionInternal( - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, - _Out_ bool* isNormalized) WI_NOEXCEPT - { - if (debugString) + inline void __stdcall Rethrow() { - *debugString = L'\0'; - } - *isNormalized = false; - - if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr) - { - const auto hr = details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized); - if (FAILED(hr)) - { - return ResultStatus::FromResult(hr); - } + throw; } - if (details::g_pfnResultFromCaughtException_WinRt != nullptr) + inline void __stdcall ThrowResultExceptionInternal(const FailureInfo &failure) { - const auto hr = details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized); - return ResultStatus::FromResult(hr); + throw ResultException(failure); } - if (g_pfnResultFromCaughtException) + __declspec(noinline) inline ResultStatus __stdcall ResultFromCaughtExceptionInternal( + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, + _Out_ bool *isNormalized) WI_NOEXCEPT { - try + if (debugString) { - throw; + *debugString = L'\0'; } - catch (const ResultException& exception) + *isNormalized = false; + + if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr) { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(E_OUTOFMEMORY); - } - catch (...) - { - auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); + const auto hr = + details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized); if (FAILED(hr)) { return ResultStatus::FromResult(hr); } } - } - else - { - try - { - throw; - } - catch (const ResultException& exception) - { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(E_OUTOFMEMORY); - } - catch (std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(__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 ResultStatus::FromResult(S_OK); - } + if (details::g_pfnResultFromCaughtException_WinRt != nullptr) + { + const auto hr = + details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized); + return ResultStatus::FromResult(hr); + } - // Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and returning - // that HRESULT. Does NOT attempt to catch unknown exceptions (which propagate). Primarily used by SEH exception - // handling techniques to stop at the point the exception is thrown. - inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) - { - if (supported == SupportedExceptions::Default) - { - supported = g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc; - } - - if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) && - ((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) || - (supported == SupportedExceptions::ThrownOrAlloc))) - { - return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor); - } - - switch (supported) - { - case SupportedExceptions::Known: - try + if (g_pfnResultFromCaughtException) { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (std::exception& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (...) - { - auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); - if (FAILED(hr)) + try { - return hr; + throw; + } + catch (const ResultException &exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); + } + catch (const std::bad_alloc &exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return ResultStatus::FromResult(E_OUTOFMEMORY); + } + catch (...) + { + auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); + if (FAILED(hr)) + { + return ResultStatus::FromResult(hr); + } + } + } + else + { + try + { + throw; + } + catch (const ResultException &exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); + } + catch (const std::bad_alloc &exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return ResultStatus::FromResult(E_OUTOFMEMORY); + } + catch (std::exception &exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return ResultStatus::FromResult(__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 ResultStatus::FromResult(S_OK); + } + + // Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and + // returning that HRESULT. Does NOT attempt to catch unknown exceptions (which propagate). Primarily used by + // SEH exception handling techniques to stop at the point the exception is thrown. + inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo &diagnostics, void *returnAddress, + SupportedExceptions supported, IFunctor &functor) + { + if (supported == SupportedExceptions::Default) + { + supported = + g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc; + } + + if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) && + ((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) || + (supported == SupportedExceptions::ThrownOrAlloc))) + { + return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor); + } + + switch (supported) + { + case SupportedExceptions::Known: + try + { + return functor.Run(); + } + catch (const ResultException &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (std::exception &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (...) + { + auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); + if (FAILED(hr)) + { + return hr; + } + + // Unknown exception + throw; } - // Unknown exception - throw; - } + case SupportedExceptions::ThrownOrAlloc: + try + { + return functor.Run(); + } + catch (const ResultException &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } - case SupportedExceptions::ThrownOrAlloc: - try - { + case SupportedExceptions::Thrown: + try + { + return functor.Run(); + } + catch (const ResultException &exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + + case SupportedExceptions::All: + try + { + return functor.Run(); + } + catch (...) + { + return wil::details::ReportFailure_CaughtException( + __R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported); + } + + case SupportedExceptions::None: return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); + + case SupportedExceptions::Default: + WI_ASSERT(false); } - case SupportedExceptions::Thrown: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } + WI_ASSERT(false); + return S_OK; + } - case SupportedExceptions::All: + inline HRESULT ResultFromExceptionSeh(const DiagnosticsInfo &diagnostics, void *returnAddress, + SupportedExceptions supported, IFunctor &functor) WI_NOEXCEPT + { + __try + { + return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor); + } + __except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) + { + WI_ASSERT(false); + RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + } + } + + __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo &diagnostics, + SupportedExceptions supported, + IFunctor &functor) WI_NOEXCEPT + { +#ifdef RESULT_DEBUG + // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions + // themselves or if the caller doesn't want to fail-fast unknown exceptions + if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions) + { + return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); + } +#endif try { return functor.Run(); } catch (...) { - return wil::details::ReportFailure_CaughtException( - __R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported); + return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS(diagnostics), + _ReturnAddress(), supported); } - - case SupportedExceptions::None: - return functor.Run(); - - case SupportedExceptions::Default: - WI_ASSERT(false); } - WI_ASSERT(false); - return S_OK; - } - - inline HRESULT ResultFromExceptionSeh( - const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT - { - __try - { - return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor); - } - __except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) - { - WI_ASSERT(false); - RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - } - - __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT - { -#ifdef RESULT_DEBUG - // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions - // themselves or if the caller doesn't want to fail-fast unknown exceptions - if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions) + __declspec(noinline) inline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo &diagnostics, + SupportedExceptions supported, + IFunctor &functor) WI_NOEXCEPT { return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); } -#endif - try - { - return functor.Run(); - } - catch (...) - { - return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), supported); - } - } - __declspec(noinline) inline HRESULT ResultFromExceptionDebug( - const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT + // Exception guard -- catch exceptions and log them (or handle them with a custom callback) + // WARNING: may throw an exception... + inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor &functor, IFunctorHost &host, + void *returnAddress) + { + try + { + return host.Run(functor); + } + catch (...) + { + // Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the + // exception or return the remapped failure. + return host.ExceptionThrown(returnAddress); + } + } + + WI_HEADER_INITIALIZATION_FUNCTION(InitializeResultExceptions, [] { + g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter; + g_pfnRethrow = Rethrow; + g_pfnThrowResultException = ThrowResultExceptionInternal; + g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal; + return 1; + }); + } + /// @endcond + + //! A lambda-based exception guard that can vary the supported exception types. + //! This function accepts a lambda and diagnostics information as its parameters and executes that lambda + //! under a try/catch(...) block. All exceptions are caught and the function reports the exception information + //! and diagnostics to telemetry on failure. An HRESULT is returned that maps to the exception. + //! + //! Note that an overload exists that does not report failures to telemetry at all. This version should be + //! preferred to that version. Also note that neither of these versions are preferred over using try catch blocks + //! to accomplish the same thing as they will be more efficient. + //! ~~~~ + //! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] + //! { + //! // exception-based code + //! // telemetry is reported with full exception information + //! }); + //! ~~~~ + //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter + //! @param supported What kind of exceptions you want to support + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template + __forceinline HRESULT ResultFromException(const DiagnosticsInfo &diagnostics, SupportedExceptions supported, + Functor &&functor) WI_NOEXCEPT { - return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); + static_assert(details::functor_tag::value != details::tag_return_other::value, + "Functor must return void or HRESULT"); + typename details::functor_tag::template functor_wrapper functorObject( + wistd::forward(functor)); + + return wil::details::ResultFromException(diagnostics, supported, functorObject); } - // Exception guard -- catch exceptions and log them (or handle them with a custom callback) - // WARNING: may throw an exception... - inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor& functor, IFunctorHost& host, void* returnAddress) + //! A lambda-based exception guard. + //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromException for more detailed + //! information. + template + __forceinline HRESULT ResultFromException(const DiagnosticsInfo &diagnostics, Functor &&functor) WI_NOEXCEPT { - try - { - return host.Run(functor); - } - catch (...) - { - // Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the exception or - // return the remapped failure. - return host.ExceptionThrown(returnAddress); - } + return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward(functor)); } - WI_HEADER_INITIALIZATION_FUNCTION(InitializeResultExceptions, [] { - g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter; - g_pfnRethrow = Rethrow; - g_pfnThrowResultException = ThrowResultExceptionInternal; - g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal; - return 1; - }); -} -/// @endcond + //! A lambda-based exception guard that does not report failures to telemetry. + //! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block. + //! All exceptions are caught and the function returns an HRESULT mapping to the exception. + //! + //! This version (taking only a lambda) does not report failures to telemetry. An overload with the same name + //! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter + //! to report failure information to telemetry. + //! ~~~~ + //! hr = wil::ResultFromException([&] + //! { + //! // exception-based code + //! // the conversion of exception to HRESULT doesn't report telemetry + //! }); + //! + //! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] + //! { + //! // exception-based code + //! // telemetry is reported with full exception information + //! }); + //! ~~~~ + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template inline HRESULT ResultFromException(Functor &&functor) WI_NOEXCEPT + try + { + static_assert(details::functor_tag::value == details::tag_return_void::value, + "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject( + wistd::forward(functor)); -//! A lambda-based exception guard that can vary the supported exception types. -//! This function accepts a lambda and diagnostics information as its parameters and executes that lambda -//! under a try/catch(...) block. All exceptions are caught and the function reports the exception information -//! and diagnostics to telemetry on failure. An HRESULT is returned that maps to the exception. -//! -//! Note that an overload exists that does not report failures to telemetry at all. This version should be preferred -//! to that version. Also note that neither of these versions are preferred over using try catch blocks to accomplish -//! the same thing as they will be more efficient. -//! ~~~~ -//! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] -//! { -//! // exception-based code -//! // telemetry is reported with full exception information -//! }); -//! ~~~~ -//! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter -//! @param supported What kind of exceptions you want to support -//! @param functor A lambda that accepts no parameters; any return value is ignored -//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown -template -__forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT -{ - static_assert(details::functor_tag::value != details::tag_return_other::value, "Functor must return void or HRESULT"); - typename details::functor_tag::template functor_wrapper functorObject( - wistd::forward(functor)); + functorObject.Run(); + return S_OK; + } + catch (...) + { + return ResultFromCaughtException(); + } - return wil::details::ResultFromException(diagnostics, supported, functorObject); -} + //! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported + //! exception types. Functionally this is nearly identical to the corresponding @ref ResultFromException function + //! with the exception that it utilizes structured exception handling internally to be able to terminate at the + //! point where a unknown exception is thrown, rather than after that unknown exception has been unwound. Though + //! less efficient, this leads to a better debugging experience when analyzing unknown exceptions. + //! + //! For example: + //! ~~~~ + //! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&] + //! { + //! FunctionWhichMayThrow(); + //! }); + //! ~~~~ + //! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`. This ends up + //! throwing a `long` as an exception object which is not what the caller intended. The normal @ref + //! ResultFromException would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() + //! is already off of the stack and has been unwound. Because SEH is used for ResultFromExceptionDebug, the + //! fail-fast occurs with everything leading up to and including the `throw INVALIDARG;` still on the stack (and + //! easily debuggable). + //! + //! The penalty paid for using this, however, is efficiency. It's far less efficient as a general pattern than + //! either using ResultFromException directly or especially using try with CATCH_ macros directly. Still it's + //! helpful to deploy selectively to isolate issues a component may be having with unknown/unhandled exceptions. + //! + //! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected + //! exceptions not falling into the supported category easily through fail-fast. For example, by not supporting any + //! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the + //! point the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be + //! tracked down. + //! + //! This will fail-fast and stop on std::exception based exceptions (but not Platform::Exception^ or + //! wil::ResultException). Using this can help isolate where an unexpected exception is being generated from. + //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter + //! @param supported What kind of exceptions you want to support + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template + __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo &diagnostics, SupportedExceptions supported, + Functor &&functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, + "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject( + wistd::forward(functor)); -//! A lambda-based exception guard. -//! This overload uses SupportedExceptions::Known by default. See @ref ResultFromException for more detailed information. -template -__forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT -{ - return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward(functor)); -} + return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject); + } -//! A lambda-based exception guard that does not report failures to telemetry. -//! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block. -//! All exceptions are caught and the function returns an HRESULT mapping to the exception. -//! -//! This version (taking only a lambda) does not report failures to telemetry. An overload with the same name -//! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter -//! to report failure information to telemetry. -//! ~~~~ -//! hr = wil::ResultFromException([&] -//! { -//! // exception-based code -//! // the conversion of exception to HRESULT doesn't report telemetry -//! }); -//! -//! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] -//! { -//! // exception-based code -//! // telemetry is reported with full exception information -//! }); -//! ~~~~ -//! @param functor A lambda that accepts no parameters; any return value is ignored -//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown -template -inline HRESULT ResultFromException(Functor&& functor) WI_NOEXCEPT -try -{ - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject( - wistd::forward(functor)); + //! A lambda-based exception guard that can identify the origin of unknown exceptions. + //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromExceptionDebug for more detailed + //! information. + template + __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo &diagnostics, Functor &&functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, + "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject( + wistd::forward(functor)); - functorObject.Run(); - return S_OK; -} -catch (...) -{ - return ResultFromCaughtException(); -} + return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject); + } -//! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported exception types. -//! Functionally this is nearly identical to the corresponding @ref ResultFromException function with the exception -//! that it utilizes structured exception handling internally to be able to terminate at the point where a unknown -//! exception is thrown, rather than after that unknown exception has been unwound. Though less efficient, this leads -//! to a better debugging experience when analyzing unknown exceptions. -//! -//! For example: -//! ~~~~ -//! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&] -//! { -//! FunctionWhichMayThrow(); -//! }); -//! ~~~~ -//! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`. This ends up -//! throwing a `long` as an exception object which is not what the caller intended. The normal @ref ResultFromException -//! would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() is already off of the -//! stack and has been unwound. Because SEH is used for ResultFromExceptionDebug, the fail-fast occurs with everything -//! leading up to and including the `throw INVALIDARG;` still on the stack (and easily debuggable). -//! -//! The penalty paid for using this, however, is efficiency. It's far less efficient as a general pattern than either -//! using ResultFromException directly or especially using try with CATCH_ macros directly. Still it's helpful to deploy -//! selectively to isolate issues a component may be having with unknown/unhandled exceptions. -//! -//! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected -//! exceptions not falling into the supported category easily through fail-fast. For example, by not supporting any -//! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the point -//! the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be tracked down. -//! -//! This will fail-fast and stop on std::exception based exceptions (but not Platform::Exception^ or wil::ResultException). -//! Using this can help isolate where an unexpected exception is being generated from. -//! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter -//! @param supported What kind of exceptions you want to support -//! @param functor A lambda that accepts no parameters; any return value is ignored -//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown -template -__forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT -{ - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject( - wistd::forward(functor)); + //! A fail-fast based exception guard. + //! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default. + //! Any uncaught exception that makes it back to this guard would result in a fail-fast at the point the exception + //! is thrown. + template + __forceinline void FailFastException(const DiagnosticsInfo &diagnostics, Functor &&functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, + "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject( + wistd::forward(functor)); - return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject); -} + wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject); + } -//! A lambda-based exception guard that can identify the origin of unknown exceptions. -//! This overload uses SupportedExceptions::Known by default. See @ref ResultFromExceptionDebug for more detailed information. -template -__forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT -{ - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject( - wistd::forward(functor)); - - return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject); -} - -//! A fail-fast based exception guard. -//! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default. Any uncaught -//! exception that makes it back to this guard would result in a fail-fast at the point the exception is thrown. -template -__forceinline void FailFastException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT -{ - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject( - wistd::forward(functor)); - - wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject); -} - -/// @cond -namespace details -{ + /// @cond + namespace details + { #endif // WIL_ENABLE_EXCEPTIONS - // Exception guard -- catch exceptions and log them (or handle them with a custom callback) - // WARNING: may throw an exception... - inline __declspec(noinline) HRESULT RunFunctor(IFunctor& functor, IFunctorHost& host) - { - if (g_pfnRunFunctorWithExceptionFilter) + // Exception guard -- catch exceptions and log them (or handle them with a custom callback) + // WARNING: may throw an exception... + inline __declspec(noinline) HRESULT RunFunctor(IFunctor &functor, IFunctorHost &host) { - return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress()); + if (g_pfnRunFunctorWithExceptionFilter) + { + return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress()); + } + + return host.Run(functor); } - return host.Run(functor); - } - - // Returns true if a debugger should be considered to be connected. - // Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging), - // they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging), - // and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call - inline bool IsDebuggerPresent() - { - return g_fIsDebuggerPresent || - ((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE)); - } - - //***************************************************************************** - // Shared Reporting -- all reporting macros bubble up through this codepath - //***************************************************************************** - - inline void LogFailure( - __R_FN_PARAMS_FULL, - FailureType type, - const ResultStatus& resultPair, - _In_opt_ PCWSTR message, - bool fWantDebugString, - _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, - _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, - _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, - _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, - FailureFlags flags, - _Out_ FailureInfo* failure) WI_NOEXCEPT - { - debugString[0] = L'\0'; - callContextString[0] = L'\0'; - - static long volatile s_failureId = 0; - - failure->hr = resultPair.hr; - failure->status = resultPair.status; - - int failureCount = 0; - switch (type) + // Returns true if a debugger should be considered to be connected. + // Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging), + // they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging), + // and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call + inline bool IsDebuggerPresent() { - case FailureType::Exception: - failureCount = RecordException(failure->hr); - break; - case FailureType::Return: - failureCount = RecordReturn(failure->hr); - break; - case FailureType::Log: + return g_fIsDebuggerPresent || + ((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE)); + } + + //***************************************************************************** + // Shared Reporting -- all reporting macros bubble up through this codepath + //***************************************************************************** + + inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus &resultPair, + _In_opt_ PCWSTR message, bool fWantDebugString, + _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, + _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, + _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, + _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, + FailureFlags flags, _Out_ FailureInfo *failure) WI_NOEXCEPT + { + debugString[0] = L'\0'; + callContextString[0] = L'\0'; + + static long volatile s_failureId = 0; + + failure->hr = resultPair.hr; + failure->status = resultPair.status; + + int failureCount = 0; + switch (type) + { + case FailureType::Exception: + failureCount = RecordException(failure->hr); + break; + case FailureType::Return: + failureCount = RecordReturn(failure->hr); + break; + case FailureType::Log: + if (SUCCEEDED(failure->hr)) + { + // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying + // to log success using one of the WIL macros. Example: + // LOG_HR(S_OK); + // Instead, use one of the forms that conditionally logs based upon the error condition: + // LOG_IF_FAILED(hr); + + WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success."); + failure->hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE); + failure->status = wil::details::HrToNtStatus(failure->hr); + } + failureCount = RecordLog(failure->hr); + break; + case FailureType::FailFast: + failureCount = RecordFailFast(failure->hr); + break; + }; + + failure->type = type; + failure->flags = flags; + WI_SetFlagIf(failure->flags, FailureFlags::NtStatus, resultPair.kind == ResultStatus::Kind::NtStatus); + failure->failureId = ::InterlockedIncrementNoFence(&s_failureId); + failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr; + failure->threadId = ::GetCurrentThreadId(); + failure->pszFile = fileName; + failure->uLineNumber = lineNumber; + failure->cFailureCount = failureCount; + failure->pszCode = code; + failure->pszFunction = functionName; + failure->returnAddress = returnAddress; + failure->callerReturnAddress = callerReturnAddress; + failure->pszCallContext = nullptr; + ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent)); + ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating)); + failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr; + + // Process failure notification / adjustments + if (details::g_pfnNotifyFailure) + { + details::g_pfnNotifyFailure(failure); + } + + // Completes filling out failure, notifies thread-based callbacks and the telemetry callback + if (details::g_pfnGetContextAndNotifyFailure) + { + details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars); + } + + // Allow hooks to inspect the failure before acting upon it + if (details::g_pfnLoggingCallback) + { + details::g_pfnLoggingCallback(*failure); + } + + // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve + // the diagnostic experience for uncaught exceptions. In cases where we will be throwing a C++/CX + // Platform::Exception we should avoid originating because the CX runtime will be doing that for us. + // fWantDebugString is only set to true when the caller will be throwing a Platform::Exception. + if (details::g_pfnOriginateCallback && !fWantDebugString && + WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry)) + { + details::g_pfnOriginateCallback(*failure); + } + if (SUCCEEDED(failure->hr)) { - // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log - // success using one of the WIL macros. Example: - // LOG_HR(S_OK); - // Instead, use one of the forms that conditionally logs based upon the error condition: - // LOG_IF_FAILED(hr); - - WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success."); - failure->hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE); + // Caller bug: Leaking a success code into a failure-only function + FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast); + failure->hr = E_UNEXPECTED; failure->status = wil::details::HrToNtStatus(failure->hr); } - failureCount = RecordLog(failure->hr); - break; - case FailureType::FailFast: - failureCount = RecordFailFast(failure->hr); - break; - }; - failure->type = type; - failure->flags = flags; - WI_SetFlagIf(failure->flags, FailureFlags::NtStatus, resultPair.kind == ResultStatus::Kind::NtStatus); - failure->failureId = ::InterlockedIncrementNoFence(&s_failureId); - failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr; - failure->threadId = ::GetCurrentThreadId(); - failure->pszFile = fileName; - failure->uLineNumber = lineNumber; - failure->cFailureCount = failureCount; - failure->pszCode = code; - failure->pszFunction = functionName; - failure->returnAddress = returnAddress; - failure->callerReturnAddress = callerReturnAddress; - failure->pszCallContext = nullptr; - ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent)); - ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating)); - failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr; + bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString && + WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry); - // Process failure notification / adjustments - if (details::g_pfnNotifyFailure) - { - details::g_pfnNotifyFailure(failure); - } - - // Completes filling out failure, notifies thread-based callbacks and the telemetry callback - if (details::g_pfnGetContextAndNotifyFailure) - { - details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars); - } - - // Allow hooks to inspect the failure before acting upon it - if (details::g_pfnLoggingCallback) - { - details::g_pfnLoggingCallback(*failure); - } - - // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience - // for uncaught exceptions. In cases where we will be throwing a C++/CX Platform::Exception we should avoid originating because the - // CX runtime will be doing that for us. fWantDebugString is only set to true when the caller will be throwing a Platform::Exception. - if (details::g_pfnOriginateCallback && !fWantDebugString && WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry)) - { - details::g_pfnOriginateCallback(*failure); - } - - if (SUCCEEDED(failure->hr)) - { - // Caller bug: Leaking a success code into a failure-only function - FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast); - failure->hr = E_UNEXPECTED; - failure->status = wil::details::HrToNtStatus(failure->hr); - } - - bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString && - WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry); - - // We need to generate the logging message if: - // * We're logging to OutputDebugString - // * OR the caller asked us to (generally for attaching to a C++/CX exception) - if (fWantDebugString || fUseOutputDebugString) - { - // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the - // console or the platform exception object if the caller desires it. - if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + // We need to generate the logging message if: + // * We're logging to OutputDebugString + // * OR the caller asked us to (generally for attaching to a C++/CX exception) + if (fWantDebugString || fUseOutputDebugString) { - g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars); + // Call the logging callback (if present) to allow them to generate the debug string that will be pushed + // to the console or the platform exception object if the caller desires it. + if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + { + g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars); + } + + // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, + // yet we still want it for OutputDebugString or exception message, then generate the default string. + if (debugString[0] == L'\0') + { + GetFailureLogString(debugString, debugStringSizeChars, *failure); + } + + if (fUseOutputDebugString) + { + ::OutputDebugStringW(debugString); + } + } + else + { + // [deprecated behavior] + // This callback was at one point *always* called for all failures, so we continue to call it for + // failures even when we don't need to generate the debug string information (when the callback was + // supplied directly). We can avoid this if the caller used the explicit function (through + // g_resultMessageCallbackSet) + if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + { + g_pfnResultLoggingCallback(failure, nullptr, 0); + } } - // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still - // want it for OutputDebugString or exception message, then generate the default string. - if (debugString[0] == L'\0') + if ((WI_IsFlagSet(failure->flags, FailureFlags::RequestDebugBreak) || g_fBreakOnFailure) && + (g_pfnDebugBreak != nullptr)) { - GetFailureLogString(debugString, debugStringSizeChars, *failure); - } - - if (fUseOutputDebugString) - { - ::OutputDebugStringW(debugString); - } - } - else - { - // [deprecated behavior] - // This callback was at one point *always* called for all failures, so we continue to call it for failures even when - // we don't need to generate the debug string information (when the callback was supplied directly). We can avoid - // this if the caller used the explicit function (through g_resultMessageCallbackSet) - if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) - { - g_pfnResultLoggingCallback(failure, nullptr, 0); + g_pfnDebugBreak(); } } - if ((WI_IsFlagSet(failure->flags, FailureFlags::RequestDebugBreak) || g_fBreakOnFailure) && (g_pfnDebugBreak != nullptr)) + inline RESULT_NORETURN void __stdcall WilFailFast(const wil::FailureInfo &failure) { - g_pfnDebugBreak(); - } - } - - inline RESULT_NORETURN void __stdcall WilFailFast(const wil::FailureInfo& failure) - { - if (g_pfnWilFailFast) - { - g_pfnWilFailFast(failure); - } + if (g_pfnWilFailFast) + { + g_pfnWilFailFast(failure); + } #ifdef RESULT_RAISE_FAST_FAIL_EXCEPTION - // Use of this macro is an ODR violation - use the callback instead. This will be removed soon. - RESULT_RAISE_FAST_FAIL_EXCEPTION; + // Use of this macro is an ODR violation - use the callback instead. This will be removed soon. + RESULT_RAISE_FAST_FAIL_EXCEPTION; #endif - // Before we fail fast in this method, give the [optional] RoFailFastWithErrorContext a try. - if (g_pfnFailfastWithContextCallback) - { - g_pfnFailfastWithContextCallback(failure); - } - - // parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT) - EXCEPTION_RECORD er{}; - er.NumberParameters = 1; // default to be safe, see below - er.ExceptionCode = static_cast(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409 - er.ExceptionFlags = EXCEPTION_NONCONTINUABLE; - er.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w - if (failure.returnAddress == nullptr) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it - { - // passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing - // !analyze functionality to crawl the stack looking for the HRESULT - // don't pass a 0 HRESULT in param 1 because that will result in worse bucketing. - WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS); - } - else // use FailureInfo caller address - { - // parameter 1 is the failing HRESULT - // parameter 2 is the line number. This is never used for bucketing (due to code churn causing re-bucketing) but is available in the dump's - // exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps. - er.NumberParameters = 3; - er.ExceptionInformation[1] = failure.hr; - er.ExceptionInformation[2] = failure.uLineNumber; - er.ExceptionAddress = failure.returnAddress; - WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */); - } - } - - template - inline __declspec(noinline) void ReportFailure_Return( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options, FailureFlags flags) - { - bool needPlatformException = - ((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && - (g_pfnThrowPlatformException != nullptr) && - (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure( - __R_FN_CALL_FULL, - T, - resultPair, - message, - needPlatformException, - debugString, - ARRAYSIZE(debugString), - callContextString, - ARRAYSIZE(callContextString), - flags, - &failure); - - if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) - { - WilFailFast(failure); - } - } - - template - inline __declspec(noinline) void ReportFailure_Base( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options, FailureFlags flags) - { - ReportFailure_Return(__R_FN_CALL_FULL, resultPair, message, options, flags); - } - - template - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_NoReturn( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - bool needPlatformException = - ((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && - (g_pfnThrowPlatformException != nullptr) && - (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure( - __R_FN_CALL_FULL, - T, - resultPair, - message, - needPlatformException, - debugString, - ARRAYSIZE(debugString), - callContextString, - ARRAYSIZE(callContextString), - FailureFlags::None, - &failure); - __WI_SUPPRESS_BREAKING_WARNINGS_S - if ((T == FailureType::FailFast) || WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) - { - WilFailFast(const_cast(failure)); - } - else - { - if (needPlatformException) + // Before we fail fast in this method, give the [optional] RoFailFastWithErrorContext a try. + if (g_pfnFailfastWithContextCallback) { - g_pfnThrowPlatformException(failure, debugString); + g_pfnFailfastWithContextCallback(failure); } - if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow)) + // parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT) + EXCEPTION_RECORD er{}; + er.NumberParameters = 1; // default to be safe, see below + er.ExceptionCode = static_cast(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409 + er.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + er.ExceptionInformation[0] = + FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w + if (failure.returnAddress == + nullptr) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it { - RethrowCaughtException(); + // passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing + // !analyze functionality to crawl the stack looking for the HRESULT + // don't pass a 0 HRESULT in param 1 because that will result in worse bucketing. + WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS); + } + else // use FailureInfo caller address + { + // parameter 1 is the failing HRESULT + // parameter 2 is the line number. This is never used for bucketing (due to code churn causing + // re-bucketing) but is available in the dump's exception record to aid in failure locality. Putting it + // here prevents it from being poisoned in triage dumps. + er.NumberParameters = 3; + er.ExceptionInformation[1] = failure.hr; + er.ExceptionInformation[2] = failure.uLineNumber; + er.ExceptionAddress = failure.returnAddress; + WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */); + } + } + + template + inline __declspec(noinline) void ReportFailure_Return(__R_FN_PARAMS_FULL, const ResultStatus &resultPair, + PCWSTR message, ReportFailureOptions options, + FailureFlags flags) + { + bool needPlatformException = + ((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && + (g_pfnThrowPlatformException != nullptr) && + (g_fResultThrowPlatformException || + WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, T, resultPair, message, needPlatformException, debugString, + ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), flags, &failure); + + if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) + { + WilFailFast(failure); + } + } + + template + inline __declspec(noinline) void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus &resultPair, + PCWSTR message, ReportFailureOptions options, + FailureFlags flags) + { + ReportFailure_Return(__R_FN_CALL_FULL, resultPair, message, options, flags); + } + + template + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_NoReturn(__R_FN_PARAMS_FULL, + const ResultStatus &resultPair, + PCWSTR message, + ReportFailureOptions options) + { + bool needPlatformException = + ((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && + (g_pfnThrowPlatformException != nullptr) && + (g_fResultThrowPlatformException || + WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, T, resultPair, message, needPlatformException, debugString, + ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), FailureFlags::None, + &failure); + __WI_SUPPRESS_BREAKING_WARNINGS_S + if ((T == FailureType::FailFast) || WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) + { + WilFailFast(const_cast(failure)); + } + else + { + if (needPlatformException) + { + g_pfnThrowPlatformException(failure, debugString); + } + + if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow)) + { + RethrowCaughtException(); + } + + ThrowResultException(failure); + + // Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are + // not setup) + WilFailFast(const_cast(failure)); + } + __WI_SUPPRESS_BREAKING_WARNINGS_E + } + + template <> + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base( + __R_FN_PARAMS_FULL, const ResultStatus &resultPair, PCWSTR message, ReportFailureOptions options, + FailureFlags) + { + ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); + } + + template <> + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base( + __R_FN_PARAMS_FULL, const ResultStatus &resultPair, PCWSTR message, ReportFailureOptions options, + FailureFlags) + { + ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); + } + + __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, + const ResultStatus &resultPair, _In_opt_ PCWSTR message, + ReportFailureOptions options) + { + switch (type) + { + case FailureType::Exception: + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); + break; + case FailureType::FailFast: + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); + break; + case FailureType::Log: + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); + break; + case FailureType::Return: + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); + break; + } + } + + template + inline ResultStatus ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, + _Inout_updates_(debugStringChars) PWSTR debugString, + _Pre_satisfies_(debugStringChars > 0) + size_t debugStringChars, + SupportedExceptions supported) + { + bool isNormalized = false; + auto length = wcslen(debugString); + WI_ASSERT(length < debugStringChars); + ResultStatus resultPair; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, + debugStringChars - length, &isNormalized); } - ThrowResultException(failure); + const bool known = (FAILED(resultPair.hr)); + if (!known) + { + resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + } - // Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup) - WilFailFast(const_cast(failure)); + ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; + WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); + + if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) || + ((supported == SupportedExceptions::Thrown) && !isNormalized) || + ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + { + // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any + // std::exception or wil::ResultException based types and Platform::Exception^, so there aren't too many + // valid exception types which could cause this. Those that are valid, should be handled by remapping + // the exception callback. Those that are not valid should be found and fixed (meaningless accidents + // like 'throw hr;'). The caller may also be requesting non-default behavior to fail-fast more + // frequently (primarily for debugging unknown exceptions). + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + } + else + { + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + } + + return resultPair; } - __WI_SUPPRESS_BREAKING_WARNINGS_E - } - template <> - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options, FailureFlags) - { - ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); - } - - template <> - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options, FailureFlags) - { - ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); - } - - __declspec(noinline) inline void ReportFailure( - __R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message, ReportFailureOptions options) - { - switch (type) + template + inline ResultStatus RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase( + __R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, + _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) { - case FailureType::Exception: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::FailFast: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::Log: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::Return: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - } - } + bool isNormalized = false; + const auto length = wcslen(debugString); + WI_ASSERT(length < debugStringChars); + ResultStatus resultPair; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, + debugStringChars - length, &isNormalized); + } - template - inline ResultStatus ReportFailure_CaughtExceptionCommon( - __R_FN_PARAMS_FULL, - _Inout_updates_(debugStringChars) PWSTR debugString, - _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, - SupportedExceptions supported) - { - bool isNormalized = false; - auto length = wcslen(debugString); - WI_ASSERT(length < debugStringChars); - ResultStatus resultPair; - if (details::g_pfnResultFromCaughtExceptionInternal) + const bool known = (FAILED(resultPair.hr)); + if (!known) + { + resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + } + + ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; + WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); + + if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) || + ((supported == SupportedExceptions::Thrown) && !isNormalized) || + ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + { + // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any + // std::exception or wil::ResultException based types and Platform::Exception^, so there aren't too many + // valid exception types which could cause this. Those that are valid, should be handled by remapping + // the exception callback. Those that are not valid should be found and fixed (meaningless accidents + // like 'throw hr;'). The caller may also be requesting non-default behavior to fail-fast more + // frequently (primarily for debugging unknown exceptions). + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + } + else + { + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + } + + RESULT_NORETURN_RESULT(resultPair); + } + + template <> + inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon( + __R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, + _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) { - resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase( + __R_FN_CALL_FULL, debugString, debugStringChars, supported)); } - const bool known = (FAILED(resultPair.hr)); - if (!known) + template <> + inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon( + __R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, + _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) { - resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase( + __R_FN_CALL_FULL, debugString, debugStringChars, supported)); } - ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; - WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); - - if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) || - ((supported == SupportedExceptions::Thrown) && !isNormalized) || - ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + template + inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus &resultPair, + _Printf_format_string_ PCSTR formatString, va_list argList) { - // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or - // wil::ResultException based types and Platform::Exception^, so there aren't too many valid exception types which - // could cause this. Those that are valid, should be handled by remapping the exception callback. Those that are not - // valid should be found and fixed (meaningless accidents like 'throw hr;'). The caller may also be requesting - // non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); } - else + + template <> + inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, + const ResultStatus &resultPair, + _Printf_format_string_ PCSTR formatString, + va_list argList) { - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); } - return resultPair; - } - - template - inline ResultStatus RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase( - __R_FN_PARAMS_FULL, - _Inout_updates_(debugStringChars) PWSTR debugString, - _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, - SupportedExceptions supported) - { - bool isNormalized = false; - const auto length = wcslen(debugString); - WI_ASSERT(length < debugStringChars); - ResultStatus resultPair; - if (details::g_pfnResultFromCaughtExceptionInternal) + template <> + inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, + const ResultStatus &resultPair, + _Printf_format_string_ PCSTR formatString, + va_list argList) { - resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); } - const bool known = (FAILED(resultPair.hr)); - if (!known) + template + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...) { - resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + va_list argList; + va_start(argList, formatString); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); } - ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; - WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); - - if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) || - ((supported == SupportedExceptions::Thrown) && !isNormalized) || - ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + template + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, FailureFlags flags) { - // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or - // wil::ResultException based types and Platform::Exception^, so there aren't too many valid exception types which - // could cause this. Those that are valid, should be handled by remapping the exception callback. Those that are not - // valid should be found and fixed (meaningless accidents like 'throw hr;'). The caller may also be requesting - // non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), nullptr /*message*/, + ReportFailureOptions::None /*options*/, flags); } - else + + template <> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, + HRESULT hr, + FailureFlags) { - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); } - RESULT_NORETURN_RESULT(resultPair); - } - - template <> - inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon( - __R_FN_PARAMS_FULL, - _Inout_updates_(debugStringChars) PWSTR debugString, - _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, - SupportedExceptions supported) - { - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase( - __R_FN_CALL_FULL, debugString, debugStringChars, supported)); - } - - template <> - inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon( - __R_FN_PARAMS_FULL, - _Inout_updates_(debugStringChars) PWSTR debugString, - _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, - SupportedExceptions supported) - { - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase( - __R_FN_CALL_FULL, debugString, debugStringChars, supported)); - } - - template - inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template <> - inline RESULT_NORETURN void ReportFailure_Msg( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template <> - inline RESULT_NORETURN void ReportFailure_Msg( - __R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template - inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } - - template - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, FailureFlags flags) - { - ReportFailure_Base( - __R_FN_CALL_FULL, ResultStatus::FromResult(hr), nullptr /*message*/, ReportFailureOptions::None /*options*/, flags); - } - - template <> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, FailureFlags) - { - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - } - - template <> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr, FailureFlags) - { - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - } - - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr) - { - switch (type) + template <> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, + HRESULT hr, + FailureFlags) { - case FailureType::Exception: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::FailFast: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::Log: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::Return: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); } - } - template - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - return hr; - } + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr) + { + switch (type) + { + case FailureType::Exception: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::FailFast: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::Log: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::Return: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + } + } - template <> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } + template + _Success_(true) _Translates_Win32_to_HRESULT_(err) __declspec(noinline) inline HRESULT + ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + return hr; + } - template <> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } + template <> + _Success_(true) _Translates_Win32_to_HRESULT_(err) __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(hr); + } - template - __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - ::SetLastError(err); - return err; - } + template <> + _Success_(true) _Translates_Win32_to_HRESULT_(err) __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(hr); + } - template <> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(err); - } + template __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + ::SetLastError(err); + return err; + } - template <> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(err); - } + template <> + __declspec(noinline) inline RESULT_NORETURN DWORD + ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(err); + } - template - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - return hr; - } + template <> + __declspec(noinline) inline RESULT_NORETURN DWORD + ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(err); + } - template <> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } + template + _Success_(true) _Translates_last_error_to_HRESULT_ __declspec(noinline) inline HRESULT + ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + return hr; + } - template <> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } + template <> + _Success_(true) _Translates_last_error_to_HRESULT_ __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(hr); + } - template - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - return resultPair.hr; - } + template <> + _Success_(true) _Translates_last_error_to_HRESULT_ __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); + RESULT_NORETURN_RESULT(hr); + } - template <> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - RESULT_NORETURN_RESULT(resultPair.hr); - } + template + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) __declspec(noinline) inline HRESULT + ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair); + return resultPair.hr; + } - template <> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - RESULT_NORETURN_RESULT(resultPair.hr); - } + template <> + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair); + RESULT_NORETURN_RESULT(resultPair.hr); + } - template - __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr; - } + template <> + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Base(__R_FN_CALL_FULL, resultPair); + RESULT_NORETURN_RESULT(resultPair.hr); + } - template <> - __declspec(noinline) inline RESULT_NORETURN HRESULT - ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - RESULT_NORETURN_RESULT( - ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr); - } + template + __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, + SupportedExceptions supported) + { + wchar_t message[2048]{}; + return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr; + } - template <> - __declspec(noinline) inline RESULT_NORETURN HRESULT - ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - RESULT_NORETURN_RESULT( - ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr); - } + template <> + __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]{}; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), supported) + .hr); + } - template - __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } + template <> + __declspec(noinline) inline RESULT_NORETURN HRESULT + ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]{}; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), supported) + .hr); + } - template <> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg( - __R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } + template + __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, + _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); + } - template <> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg( - __R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } + template <> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg( + __R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + } - template - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - return hr; - } + template <> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg( + __R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + } - template <> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg( - __R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } + template + _Success_(true) _Translates_Win32_to_HRESULT_(err) __declspec(noinline) inline HRESULT + ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, + va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); + return hr; + } - template <> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg( - __R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } + template <> + _Success_(true) _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg( + __R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(hr); + } - template - __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - ::SetLastError(err); - return err; - } + template <> + _Success_(true) _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg( + __R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(hr); + } - template <> - __declspec(noinline) inline RESULT_NORETURN DWORD - ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(err); - } + template + __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, + _Printf_format_string_ PCSTR formatString, + va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); + ::SetLastError(err); + return err; + } - template <> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg( - __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(err); - } + template <> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg( + __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(err); + } - template - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - return hr; - } + template <> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg( + __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(err); + } - template <> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg( - __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } + template + _Success_(true) _Translates_last_error_to_HRESULT_ __declspec(noinline) inline HRESULT + ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, + va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); + return hr; + } - template <> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg( - __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } + template <> + _Success_(true) _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg( + __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(hr); + } - template - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg( - __R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - return resultPair.hr; - } + template <> + _Success_(true) _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg( + __R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, + argList); + RESULT_NORETURN_RESULT(hr); + } - template <> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg( - __R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - RESULT_NORETURN_RESULT(resultPair.hr); - } + template + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) __declspec(noinline) inline HRESULT + ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, + va_list argList) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); + return resultPair.hr; + } - template <> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg( - __R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - RESULT_NORETURN_RESULT(resultPair.hr); - } + template <> + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg( + __R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); + RESULT_NORETURN_RESULT(resultPair.hr); + } - template - __declspec(noinline) inline HRESULT ReportFailure_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(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).hr; - } + template <> + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg( + __R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + const auto resultPair = ResultStatus::FromStatus(status); + ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); + RESULT_NORETURN_RESULT(resultPair.hr); + } - template <> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_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" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( - __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) - .hr); - } + template + __declspec(noinline) inline HRESULT ReportFailure_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(__R_FN_CALL_FULL, message, ARRAYSIZE(message), + SupportedExceptions::Default) + .hr; + } - template <> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_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" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( - __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) - .hr); - } + template <> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_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" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) + .hr); + } - //***************************************************************************** - // Support for throwing custom exception types - //***************************************************************************** + template <> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_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" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon( + __R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default) + .hr); + } + + //***************************************************************************** + // Support for throwing custom exception types + //***************************************************************************** #ifdef WIL_ENABLE_EXCEPTIONS - inline HRESULT GetErrorCode(_In_ ResultException& exception) WI_NOEXCEPT - { - return exception.GetErrorCode(); - } + inline HRESULT GetErrorCode(_In_ ResultException &exception) WI_NOEXCEPT + { + return exception.GetErrorCode(); + } - inline void SetFailureInfo(_In_ FailureInfo const& failure, _Inout_ ResultException& exception) WI_NOEXCEPT - { - return exception.SetFailureInfo(failure); - } + inline void SetFailureInfo(_In_ FailureInfo const &failure, _Inout_ ResultException &exception) WI_NOEXCEPT + { + return exception.SetFailureInfo(failure); + } - // clang-format off + // clang-format off #ifdef __cplusplus_winrt inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT { @@ -5201,2133 +5271,2291 @@ namespace details // exist to distinguish this from ResultException } #endif - // clang-format on + // clang-format on - template - RESULT_NORETURN inline void ReportFailure_CustomExceptionHelper(_Inout_ T& exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr) - { - // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'" - // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h. - // This compilation error indicates an attempt to throw an incompatible exception type. - const HRESULT hr = GetErrorCode(exception); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure( - __R_FN_CALL_FULL, - FailureType::Exception, - ResultStatus::FromResult(hr), - message, - false, // false = does not need debug string - debugString, - ARRAYSIZE(debugString), - callContextString, - ARRAYSIZE(callContextString), - FailureFlags::None, - &failure); - - if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) + template + RESULT_NORETURN inline void ReportFailure_CustomExceptionHelper(_Inout_ T &exception, __R_FN_PARAMS_FULL, + _In_opt_ PCWSTR message = nullptr) { - WilFailFast(failure); - } + // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'" + // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with + // ResultException.h. This compilation error indicates an attempt to throw an incompatible exception type. + const HRESULT hr = GetErrorCode(exception); - // push the failure info context into the custom exception class - SetFailureInfo(failure, exception); + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; - throw exception; - } + LogFailure(__R_FN_CALL_FULL, FailureType::Exception, ResultStatus::FromResult(hr), message, + false, // false = does not need debug string + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), + FailureFlags::None, &failure); - template - __declspec(noinline) RESULT_NORETURN inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception) - { - __R_FN_LOCALS_RA; - ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL); - } - - template - __declspec(noinline) RESULT_NORETURN inline void ReportFailure_CustomExceptionMsg( - __R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - - __R_FN_LOCALS_RA; - ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message); - } -#endif - - namespace __R_NS_NAME - { - //***************************************************************************** - // Return Macros - //***************************************************************************** - - __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - } - - __R_DIRECT_METHOD(void, Return_HrSuppressTelemetry)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - const FailureFlags flags = FailureFlags::RequestSuppressTelemetry; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr, flags); - } - - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - } - - _Success_(true) - _Translates_last_error_to_HRESULT_ - __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY); - } - - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } -#endif - - __R_DIRECT_METHOD(void, Return_HrMsg) - (__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - } - - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __R_DIRECT_METHOD(HRESULT, Return_Win32Msg) - (__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - } - - _Success_(true) - _Translates_last_error_to_HRESULT_ - __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg) - (__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorHrMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg) - (__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, 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::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } -#endif - - //***************************************************************************** - // Log Macros - //***************************************************************************** - - _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - return hr; - } - - _Post_satisfies_(return == err) __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - return err; - } - - __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); - } - - _Post_satisfies_(return == status) __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - return status; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } -#endif - - __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); - } - - __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); - } - - __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); - } - - __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == hr) __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) - { - if (FAILED(hr)) + if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + WilFailFast(failure); } - return hr; + + // push the failure info context into the custom exception class + SetFailureInfo(failure, exception); + + throw exception; } - _Post_satisfies_(return == hr) __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, unsigned int expectedCount, ...) WI_NOEXCEPT + template + __declspec(noinline) RESULT_NORETURN inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception) { - va_list args; - va_start(args, expectedCount); + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL); + } - if (FAILED(hr)) + template + __declspec(noinline) RESULT_NORETURN inline void ReportFailure_CustomExceptionMsg( + __R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message); + } +#endif + + namespace __R_NS_NAME + { + //***************************************************************************** + // Return Macros + //***************************************************************************** + + __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT { - unsigned int expectedIndex; - for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex) + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); + } + + __R_DIRECT_METHOD(void, Return_HrSuppressTelemetry)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + const FailureFlags flags = FailureFlags::RequestSuppressTelemetry; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr, flags); + } + + _Success_(true) _Translates_Win32_to_HRESULT_(err) + __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); + } + + _Success_(true) _Translates_last_error_to_HRESULT_ + __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY); + } + + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) + __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); + } +#endif + + __R_DIRECT_METHOD(void, Return_HrMsg) + (__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); + } + + _Success_(true) _Translates_Win32_to_HRESULT_(err) + __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, + argList); + } + + _Success_(true) _Translates_last_error_to_HRESULT_ __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)( + __R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHrMsg( + __R_DIRECT_FN_CALL formatString, argList); + } + + _Success_(true) _Translates_NTSTATUS_to_HRESULT_(status) + __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, + formatString, argList); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, 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::ReportFailure_CaughtExceptionMsg( + __R_DIRECT_FN_CALL formatString, argList); + } +#endif + + //***************************************************************************** + // Log Macros + //***************************************************************************** + + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); + return hr; + } + + _Post_satisfies_(return == err) + __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); + return err; + } + + __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); + } + + _Post_satisfies_(return == status) + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); + return status; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); + } +#endif + + __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); + } + + __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); + } + + __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); + } + + __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); + } + + __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == hr) + __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) + { + if (FAILED(hr)) { - if (hr == va_arg(args, HRESULT)) + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + _Post_satisfies_(return == hr) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + unsigned int expectedCount, + ...) WI_NOEXCEPT + { + va_list args; + va_start(args, expectedCount); + + if (FAILED(hr)) + { + unsigned int expectedIndex; + for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex) { - break; + if (hr == va_arg(args, HRESULT)) + { + break; + } + } + + if (expectedIndex == expectedCount) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); } } - if (expectedIndex == expectedCount) + va_end(args); + return hr; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == ret) + __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) + { + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == err) + __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) + { + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == handle) + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == handle) + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT &pointer) + WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer) WI_NOEXCEPT + { + if (pointer == nullptr) { __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); } } - va_end(args); - return hr; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == ret) __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) - { - if (!ret) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; } - return ret; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == err) __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) { - __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err); + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; } - return err; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == handle) __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == INVALID_HANDLE_VALUE) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; } - return handle; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == handle) __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == nullptr) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)( + __R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } } - return handle; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == status) + __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) { - __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); + return hr; } - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (condition) + _Post_satisfies_(return == err) + __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); + return err; } - return condition; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (!condition) + __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg) + (__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, + argList); } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == status) + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, + argList); + return status; } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (!condition) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == status) - __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) - { - if (FAILED_NTSTATUS(status)) - { - __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status); - } - return status; - } - - _Post_satisfies_(return == hr) - __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - return hr; - } - - _Post_satisfies_(return == err) - __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - return err; - } - - __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg) - (__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - _Post_satisfies_(return == status) __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)( - __R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - return status; - } #ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Log_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::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } + __R_DIRECT_METHOD(HRESULT, Log_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::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, + argList); + } #endif - __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg) - (__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } - - _Post_satisfies_(return == hr) __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED(hr)) + __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, + argList); } - return hr; - } - _Post_satisfies_(return == ret) __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)( - __R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!ret) + __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg( + __R_INTERNAL_NOINLINE_FN_CALL formatString, argList); } - return ret; - } - _Post_satisfies_(return == err) __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)( - __R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_WIN32(err)) + __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg) + (__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, + argList); } - return err; - } - _Post_satisfies_(return == handle) __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)( - __R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) + __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, + formatString, argList); } - return handle; - } - _Post_satisfies_(return == handle) __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)( - __R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == nullptr) + __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, + va_list argList) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, + formatString, argList); } - return handle; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)( - __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == hr) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return hr; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)( - __R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == ret) __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)( + __R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; } - } - _Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) + _Post_satisfies_(return == err) + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, + argList); + } + return err; } - return condition; - } - _Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) + _Post_satisfies_(return == handle) __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)( + __R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == handle) + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)( - __R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; } - } - _Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)( - __R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)( + __R_CONDITIONAL_FN_PARAMS const PointerT &pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } } - return condition; - } - _Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)( - __R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return condition; } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)( - __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return condition; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)( - __R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)( + __R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return pointer; } - } - _Post_satisfies_(return == status) __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)( - __R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } } - return status; - } - } // namespace __R_NS_NAME - namespace __RFF_NS_NAME - { - //***************************************************************************** - // FailFast Macros - //***************************************************************************** + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + _Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)( + __R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD( + PointerT, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)( + __R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)( + __R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + } // namespace __R_NS_NAME + + namespace __RFF_NS_NAME { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL hr); - } + //***************************************************************************** + // FailFast Macros + //***************************************************************************** - __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL err); - } + __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL hr); + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL_ONLY); - } + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL err); + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL status); - } + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL_ONLY); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL status); + } #ifdef WIL_ENABLE_EXCEPTIONS - __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_CaughtException(__RFF_DIRECT_FN_CALL_ONLY); - } + __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_CaughtException(__RFF_DIRECT_FN_CALL_ONLY); + } #endif - __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL hr); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL_ONLY); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL err); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL status); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr)) + __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL hr); } - return hr; - } - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT - { - if (!ret) + __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL_ONLY); } - return ret; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) + __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL err); } - return err; - } - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) + __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY); } - return handle; - } - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull) - (__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT - { - if (handle == nullptr) + __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL status); } - return handle; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return hr; } - return pointer; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(BOOL, + FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (!ret) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return ret; } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT - { - if (condition) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + if (FAILED_WIN32(err)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err); + } + return err; } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT - { - if (!condition) + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) + WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + if (handle == INVALID_HANDLE_VALUE) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; } - return condition; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull) - (__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, + FailFast_IfHandleNull)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + if (handle == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; } - return pointer; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (condition) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, + FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT &pointer) { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (!condition) + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; } - return condition; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition) WI_NOEXCEPT { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; } - return pointer; - } - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, + FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + _Pre_maybenull_ PointerT pointer) { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return pointer; } - } - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer) { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } } - return status; - } - __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg) - (__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL hr, formatString, argList); - } + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD( + bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg) - (__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL err, formatString, argList); - } + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD( + bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg) - (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL formatString, argList); - } + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } - __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg) - (__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL status, formatString, argList); - } + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)( + __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)( + __RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg) + (__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL hr, formatString, + argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg) + (__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL err, formatString, + argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg) + (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL formatString, + argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg) + (__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL status, + formatString, argList); + } #ifdef WIL_ENABLE_EXCEPTIONS - __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg) - (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_CaughtExceptionMsg(__RFF_DIRECT_FN_CALL formatString, argList); - } + __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg) + (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_CaughtExceptionMsg(__RFF_DIRECT_FN_CALL formatString, + argList); + } #endif - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL hr, + formatString, argList); + } - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg( + __RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList); + } - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL err, + formatString, argList); + } - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, + formatString, argList); + } - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, + va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL status, + formatString, argList); + } - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg) - (__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED(hr)) + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, + FailFast_IfFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)( + __RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, + FailFast_IfWin32ErrorMsg)(__RFF_CONDITIONAL_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)( + __RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, + FailFast_IfHandleNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)( + __RFF_CONDITIONAL_FN_PARAMS const PointerT &pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, + FailFast_HrIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg)( + __RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, + FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)( + __RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)( + __RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, + FailFast_GetLastErrorIfNullMsg)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)( + __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)( + __RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL E_UNEXPECTED); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_UNEXPECTED); + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) + _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)( + __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg) + (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { va_list argList; va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL E_UNEXPECTED, + formatString, argList); } - return hr; - } - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg) - (__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!ret) + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg) + (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, + formatString, argList); } - return ret; - } - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg) - (__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_WIN32(err)) + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; } - return err; - } - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg) - (__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, + _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; } - return handle; - } - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg) - (__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == nullptr) + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg)( + __RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; } - return handle; - } - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)( + __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer, _Printf_format_string_ PCSTR formatString, + ...) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) + (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } } - return pointer; - } - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)( - __RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + //***************************************************************************** + // FailFast Immediate Macros + //***************************************************************************** + + __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + __fastfail(FAST_FAIL_FATAL_APP_EXIT); } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg) - (__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) + __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __fastfail(FAST_FAIL_FATAL_APP_EXIT); } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg) - (__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return hr; } - return condition; - } - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg) - (__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; } - return pointer; - } - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_HrIfNullMsg)( - __RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg) - (__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, + FailFastImmediate_IfNull)(_Pre_maybenull_ PointerT pointer) { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return pointer; } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg) - (__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)(_In_opt_ const PointerT &pointer) { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } } - return condition; - } - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNullMsg) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return status; } - return pointer; - } + } // namespace __RFF_NS_NAME - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)( - __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + namespace __R_NS_NAME { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg) - (__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); - } - return status; - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL E_UNEXPECTED); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_UNEXPECTED); - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)( - __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg) - (__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL E_UNEXPECTED, formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg) - (__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, formatString, argList); - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg) - (__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg) - (__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg) - (__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return pointer; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)( - __RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg) - (__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - //***************************************************************************** - // FailFast Immediate Macros - //***************************************************************************** - - __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT - { - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT - { - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return hr; - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull) - (_Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)(_In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return status; - } - } // namespace __RFF_NS_NAME - - namespace __R_NS_NAME - { - //***************************************************************************** - // Exception Macros - //***************************************************************************** + //***************************************************************************** + // Exception Macros + //***************************************************************************** #ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - } - - __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - } - - __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); - } - - __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - } - - __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); - } - - __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); - } - - __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) - { - if (FAILED(hr)) + __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); } - return hr; - } - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) - { - if (!ret) + __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); } - return ret; - } - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) + __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) { - __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); } - return err; - } - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == INVALID_HANDLE_VALUE) + __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); } - return handle; - } - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == nullptr) + __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + __R_FN_LOCALS; + wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); } - return handle; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc) - (__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) { - __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) - { - if (pointer == nullptr) + __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) { - __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (condition) + __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (!condition) + __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + if (FAILED(hr)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_Win32If)(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition) - { - if (condition) + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) { - __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; } - return condition; - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (condition) + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (!condition) + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull) - (__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, + Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; } - } - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) - { - if (FAILED_NTSTATUS(status)) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT &pointer) { - __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status); + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } } - return status; - } - __R_DIRECT_NORET_METHOD(void, Throw_HrMsg) - (__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - } + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } - __R_DIRECT_NORET_METHOD(void, Throw_Win32Msg) - (__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - } + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } - __R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); - } + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, + Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } - __R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg) - (__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - } + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } - __R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg) - (__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_Win32If)(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return condition; + } - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg) - (__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)( + __R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg) - (__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) + { + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; + } - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED(hr)) + __R_DIRECT_NORET_METHOD(void, Throw_HrMsg) + (__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) { va_list argList; va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); } - return hr; - } - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg) - (__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) - { - if (!ret) + __R_DIRECT_NORET_METHOD(void, Throw_Win32Msg) + (__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) { va_list argList; va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, + argList); } - return ret; - } - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg) - (__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED_WIN32(err)) + __R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)( + __R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) { va_list argList; va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, + argList); } - return err; - } - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg) - (__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) - { - if (handle == INVALID_HANDLE_VALUE) + __R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg) + (__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) { va_list argList; va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, + argList); } - return handle; - } - _Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg) - (__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) - { - if (handle == nullptr) + __R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg) + (__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) { va_list argList; va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, + argList); } - return handle; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg) - (__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, + formatString, argList); } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg) - (__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg( + __R_INTERNAL_NOINLINE_FN_CALL formatString, argList); } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg) + (__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, + formatString, argList); } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (!condition) + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, + formatString, argList); } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg) + (__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, + va_list argList) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, + formatString, argList); } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg) - (__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _Printf_format_string_ PCSTR formatString, + ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return hr; } - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_Win32IfMsg) - (__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(BOOL, + Throw_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, + _Printf_format_string_ PCSTR formatString, + ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; } - return condition; - } - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg) - (__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, + _Printf_format_string_ PCSTR formatString, + ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, + formatString, argList); + } + return err; } - return condition; - } - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg) - (__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (!condition) + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, + Throw_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, + _Printf_format_string_ PCSTR formatString, + ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; } - return condition; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg) - (__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + _Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, + Throw_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, + _Printf_format_string_ PCSTR formatString, ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; } - return pointer; - } - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg) - (__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; } - } - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg) - (__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED_NTSTATUS(status)) + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg)( + __R_CONDITIONAL_FN_PARAMS const PointerT &pointer, _Printf_format_string_ PCSTR formatString, ...) { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg) - (__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition, + _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + bool condition, + _Printf_format_string_ PCSTR formatString, + ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) + _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg)( + __R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, + Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, + _In_opt_ const PointerT &pointer, + _Printf_format_string_ PCSTR formatString, + ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, + argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_Win32IfMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, + bool condition, + _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, + formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, + Throw_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, + _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, + Throw_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, + _Printf_format_string_ PCSTR formatString, + ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)( + __R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, + _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg)( + __R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT &pointer, + _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)( + __R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, + Throw_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, + _Printf_format_string_ PCSTR formatString, + ...) + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg) + (__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; } - return status; - } #endif // WIL_ENABLE_EXCEPTIONS - } // namespace __R_NS_NAME -} // namespace details -/// @endcond + } // namespace __R_NS_NAME + } // namespace details + /// @endcond -//***************************************************************************** -// Error Handling Policies to switch between error-handling style -//***************************************************************************** -// The following policies are used as template policies for components that can support exception, fail-fast, and -// error-code based modes. + //***************************************************************************** + // Error Handling Policies to switch between error-handling style + //***************************************************************************** + // The following policies are used as template policies for components that can support exception, fail-fast, and + // error-code based modes. -// Use for classes which should return HRESULTs as their error-handling policy -// Intentionally removed logging from this policy as logging is more useful at the caller. -struct err_returncode_policy -{ - using result = HRESULT; + // Use for classes which should return HRESULTs as their error-handling policy + // Intentionally removed logging from this policy as logging is more useful at the caller. + struct err_returncode_policy + { + using result = HRESULT; - __forceinline static HRESULT Win32BOOL(BOOL fReturn) - { - RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn); - return S_OK; - } - __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE* ph) - { - *ph = h; - RETURN_LAST_ERROR_IF_NULL_EXPECTED(h); - return S_OK; - } - _Post_satisfies_(return == hr) __forceinline static HRESULT HResult(HRESULT hr) - { - return hr; - } - __forceinline static HRESULT LastError() - { - return wil::details::GetLastErrorFailHr(); - } - __forceinline static HRESULT LastErrorIfFalse(bool condition) - { - RETURN_LAST_ERROR_IF_EXPECTED(!condition); - return S_OK; - } - _Post_satisfies_(return == S_OK) __forceinline static HRESULT OK() - { - return S_OK; - } -}; + __forceinline static HRESULT Win32BOOL(BOOL fReturn) + { + RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn); + return S_OK; + } + __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE *ph) + { + *ph = h; + RETURN_LAST_ERROR_IF_NULL_EXPECTED(h); + return S_OK; + } + _Post_satisfies_(return == hr) __forceinline static HRESULT HResult(HRESULT hr) + { + return hr; + } + __forceinline static HRESULT LastError() + { + return wil::details::GetLastErrorFailHr(); + } + __forceinline static HRESULT LastErrorIfFalse(bool condition) + { + RETURN_LAST_ERROR_IF_EXPECTED(!condition); + return S_OK; + } + _Post_satisfies_(return == S_OK) __forceinline static HRESULT OK() + { + return S_OK; + } + }; -// Use for classes which fail-fast on errors -struct err_failfast_policy -{ - typedef _Return_type_success_(true) void result; - __forceinline static result Win32BOOL(BOOL fReturn) + // Use for classes which fail-fast on errors + struct err_failfast_policy { - FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); - } - __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph) - { - *ph = h; - FAIL_FAST_LAST_ERROR_IF_NULL(h); - } - _When_(FAILED(hr), _Analysis_noreturn_) - __forceinline static result HResult(HRESULT hr) - { - FAIL_FAST_IF_FAILED(hr); - } - __forceinline static result LastError() - { - FAIL_FAST_LAST_ERROR(); - } - __forceinline static result LastErrorIfFalse(bool condition) - { - if (!condition) + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) + { + FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); + } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) + { + *ph = h; + FAIL_FAST_LAST_ERROR_IF_NULL(h); + } + _When_(FAILED(hr), _Analysis_noreturn_) __forceinline static result HResult(HRESULT hr) + { + FAIL_FAST_IF_FAILED(hr); + } + __forceinline static result LastError() { FAIL_FAST_LAST_ERROR(); } - } - __forceinline static result OK() - { - } -}; + __forceinline static result LastErrorIfFalse(bool condition) + { + if (!condition) + { + FAIL_FAST_LAST_ERROR(); + } + } + __forceinline static result OK() + { + } + }; #ifdef WIL_ENABLE_EXCEPTIONS -// Use for classes which should return through exceptions as their error-handling policy -struct err_exception_policy -{ - typedef _Return_type_success_(true) void result; - __forceinline static result Win32BOOL(BOOL fReturn) + // Use for classes which should return through exceptions as their error-handling policy + struct err_exception_policy { - THROW_IF_WIN32_BOOL_FALSE(fReturn); - } - __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph) - { - *ph = h; - THROW_LAST_ERROR_IF_NULL(h); - } - _When_(FAILED(hr), _Analysis_noreturn_) - __forceinline static result HResult(HRESULT hr) - { - THROW_IF_FAILED(hr); - } - __forceinline static result LastError() - { - THROW_LAST_ERROR(); - } - __forceinline static result LastErrorIfFalse(bool condition) - { - if (!condition) + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) + { + THROW_IF_WIN32_BOOL_FALSE(fReturn); + } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) + { + *ph = h; + THROW_LAST_ERROR_IF_NULL(h); + } + _When_(FAILED(hr), _Analysis_noreturn_) __forceinline static result HResult(HRESULT hr) + { + THROW_IF_FAILED(hr); + } + __forceinline static result LastError() { THROW_LAST_ERROR(); } - } - __forceinline static result OK() - { - } -}; + __forceinline static result LastErrorIfFalse(bool condition) + { + if (!condition) + { + THROW_LAST_ERROR(); + } + } + __forceinline static result OK() + { + } + }; #else -// NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined -// (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at -// template instantiation time since this type lacks required member functions. An alternative would be to have some -// 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available, -// but that may have unexpected side effects when compiling code that expects to be using exceptions -struct err_exception_policy -{ -}; + // NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined + // (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at + // template instantiation time since this type lacks required member functions. An alternative would be to have some + // 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available, + // but that may have unexpected side effects when compiling code that expects to be using exceptions + struct err_exception_policy + { + }; #endif } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_originate.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_originate.h index fd563ea..431356f 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_originate.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/result_originate.h @@ -11,114 +11,119 @@ //! @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. +// 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 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. +// 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 "com.h" +#include "resource.h" #include "result.h" #include // RestrictedErrorInfo uses BSTRs :( -#include -#include "resource.h" -#include "com.h" #include +#include 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 + /// @cond + namespace details { - if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception)) + // 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 { - bool shouldOriginate = true; + if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception)) + { + bool shouldOriginate = true; + wil::com_ptr_nothrow 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(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 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))) + &descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) && + (existingHr == failure.hr)) { - shouldOriginate = (failure.hr != existingHr); + // 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()); } } - - 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(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 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 details + /// @endcond } // namespace wil // Automatically call RoOriginateError upon error origination by including this file diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/rpc_helpers.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/rpc_helpers.h index eb1741d..0f062ea 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/rpc_helpers.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/rpc_helpers.h @@ -13,206 +13,199 @@ #ifndef __WIL_RPC_HELPERS_INCLUDED #define __WIL_RPC_HELPERS_INCLUDED -#include "result.h" #include "resource.h" +#include "result.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 - struct call_adapter + /// @cond + namespace details { - template - static HRESULT call(TArgs&&... args) + // 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 struct call_adapter { - return wistd::invoke(wistd::forward(args)...); - } - }; + template static HRESULT call(TArgs &&...args) + { + return wistd::invoke(wistd::forward(args)...); + } + }; - template <> - struct call_adapter - { - template - static HRESULT call(TArgs&&... args) + template <> struct call_adapter { - wistd::invoke(wistd::forward(args)...); + template static HRESULT call(TArgs &&...args) + { + wistd::invoke(wistd::forward(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 state; + HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put()); + RETURN_IF_FAILED(hr); + ~~~ + */ + template 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)' + using result_t = typename wistd::__invoke_of::type; + RETURN_IF_FAILED(details::call_adapter::call(wistd::forward(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 state; -HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put()); -RETURN_IF_FAILED(hr); -~~~ -*/ -template -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)' - using result_t = typename wistd::__invoke_of::type; - RETURN_IF_FAILED(details::call_adapter::call(wistd::forward(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 -HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT -{ - RpcTryExcept - { - result = wistd::invoke(wistd::forward(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 - struct rpc_closer_t - { - static void Close(TStorage arg) WI_NOEXCEPT + RpcExcept(RpcExceptionFilter(RpcExceptionCode())) { - LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg)); + RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); } - }; -} // namespace details -/// @endcond + RpcEndExcept + } -/** 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. + /** 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. -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; -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 -using unique_rpc_context_handle = - unique_any::Close), details::rpc_closer_t::Close>; + 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 + HRESULT invoke_rpc_result_nothrow(TResult &result, TCall &&...args) WI_NOEXCEPT + { + RpcTryExcept + { + result = wistd::invoke(wistd::forward(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 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; + 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 + using unique_rpc_context_handle = + unique_any::Close), + details::rpc_closer_t::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 state; -wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put()); -// use 'state' -@endcode -*/ -template -void invoke_rpc(TCall&&... args) -{ - THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward(args)...)); -} + /** 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 state; + wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put()); + // use 'state' + @endcode + */ + template void invoke_rpc(TCall &&...args) + { + THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward(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 -auto invoke_rpc_result(TCall&&... args) -{ - using result_t = typename wistd::__invoke_of::type; - result_t result{}; - THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward(args)...)); - return result; -} + /** 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 auto invoke_rpc_result(TCall &&...args) + { + using result_t = typename wistd::__invoke_of::type; + result_t result{}; + THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward(args)...)); + return result; + } #endif } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/safecast.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/safecast.h index a1014a5..18568af 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/safecast.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/safecast.h @@ -14,388 +14,354 @@ #define __WIL_SAFECAST_INCLUDED #include "result_macros.h" -#include #include "wistd_config.h" #include "wistd_type_traits.h" +#include namespace wil { -/// @cond -namespace details -{ - // Default error case for undefined conversions in intsafe.h - template - constexpr wistd::nullptr_t intsafe_conversion = nullptr; + /// @cond + namespace details + { + // Default error case for undefined conversions in intsafe.h + template 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 - constexpr bool is_known_safe_static_cast_v = - (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v && wistd::is_unsigned_v)) || - (sizeof(NewT) == sizeof(OldT) && - ((wistd::is_signed_v && wistd::is_signed_v) || (wistd::is_unsigned_v && wistd::is_unsigned_v))); + // 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 + constexpr bool is_known_safe_static_cast_v = + (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v && wistd::is_unsigned_v)) || + (sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v && wistd::is_signed_v) || + (wistd::is_unsigned_v && wistd::is_unsigned_v))); - // Helper template to determine that NewT and OldT are both integral types. The safe_cast - // operation only supports conversions between integral types. - template - constexpr bool both_integral_v = wistd::is_integral::value && wistd::is_integral::value; + // Helper template to determine that NewT and OldT are both integral types. The safe_cast + // operation only supports conversions between integral types. + template + constexpr bool both_integral_v = wistd::is_integral::value && wistd::is_integral::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 - constexpr bool is_sign_extending_cast_v = - (sizeof(NewT) >= sizeof(OldT)) && both_integral_v && wistd::is_signed_v; + // 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 + constexpr bool is_sign_extending_cast_v = + (sizeof(NewT) >= sizeof(OldT)) && both_integral_v && wistd::is_signed_v; - // 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. + // 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 - constexpr bool neither_native_wchar_v = !wistd::is_same::value && !wistd::is_same::value; + // Intsafe does not have a defined conversion for native wchar_t + template + constexpr bool neither_native_wchar_v = + !wistd::is_same::value && !wistd::is_same::value; - // Check to see if the cast is a conversion to native wchar_t - template - constexpr bool is_cast_to_wchar_v = wistd::is_same::value && !wistd::is_same::value; + // Check to see if the cast is a conversion to native wchar_t + template + constexpr bool is_cast_to_wchar_v = + wistd::is_same::value && !wistd::is_same::value; - // Check to see if the cast is a conversion from native wchar_t - template - constexpr bool is_cast_from_wchar_v = !wistd::is_same::value && wistd::is_same::value; + // Check to see if the cast is a conversion from native wchar_t + template + constexpr bool is_cast_from_wchar_v = + !wistd::is_same::value && wistd::is_same::value; - // Validate the conversion to be performed has a defined mapping to an intsafe conversion - template - constexpr bool is_supported_intsafe_cast_v = intsafe_conversion != nullptr; + // Validate the conversion to be performed has a defined mapping to an intsafe conversion + template + constexpr bool is_supported_intsafe_cast_v = intsafe_conversion != nullptr; - // True when the conversion is between integral types and can be handled by static_cast - template - constexpr bool is_supported_safe_static_cast_v = both_integral_v && is_known_safe_static_cast_v; + // True when the conversion is between integral types and can be handled by static_cast + template + constexpr bool is_supported_safe_static_cast_v = + both_integral_v && is_known_safe_static_cast_v; - // True when the conversion is between integral types, does not involve native wchar, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_no_wchar_v = - both_integral_v && !is_known_safe_static_cast_v && neither_native_wchar_v && - is_supported_intsafe_cast_v; + // True when the conversion is between integral types, does not involve native wchar, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_no_wchar_v = + both_integral_v && !is_known_safe_static_cast_v && + neither_native_wchar_v && is_supported_intsafe_cast_v; - // True when the conversion is between integral types, is a cast to native wchar_t, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_to_wchar_v = - both_integral_v && !is_known_safe_static_cast_v && is_cast_to_wchar_v && - is_supported_intsafe_cast_v; + // True when the conversion is between integral types, is a cast to native wchar_t, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_to_wchar_v = + both_integral_v && !is_known_safe_static_cast_v && is_cast_to_wchar_v && + is_supported_intsafe_cast_v; - // True when the conversion is between integral types, is a cast from native wchar_t, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_from_wchar_v = - both_integral_v && !is_known_safe_static_cast_v && is_cast_from_wchar_v && - is_supported_intsafe_cast_v; + // True when the conversion is between integral types, is a cast from native wchar_t, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_from_wchar_v = + both_integral_v && !is_known_safe_static_cast_v && + is_cast_from_wchar_v && is_supported_intsafe_cast_v; - // True when the conversion is supported and unsafe, and may or may not involve - // native wchar_t. - template - constexpr bool is_supported_unsafe_cast_v = - is_supported_unsafe_cast_no_wchar_v || is_supported_unsafe_cast_to_wchar_v || - is_supported_unsafe_cast_from_wchar_v; + // True when the conversion is supported and unsafe, and may or may not involve + // native wchar_t. + template + constexpr bool is_supported_unsafe_cast_v = + is_supported_unsafe_cast_no_wchar_v || is_supported_unsafe_cast_to_wchar_v || + is_supported_unsafe_cast_from_wchar_v; - // True when T is any one of the primitive types that the variably sized types are defined as. - template - constexpr bool is_potentially_variably_sized_type_v = - wistd::is_same::value || wistd::is_same::value || wistd::is_same::value || - wistd::is_same::value || wistd::is_same::value || wistd::is_same::value; + // True when T is any one of the primitive types that the variably sized types are defined as. + template + constexpr bool is_potentially_variably_sized_type_v = + wistd::is_same::value || wistd::is_same::value || wistd::is_same::value || + wistd::is_same::value || wistd::is_same::value || + wistd::is_same::value; - // True when either type is potentially variably sized (e.g. size_t, ptrdiff_t) - template - constexpr bool is_potentially_variably_sized_cast_v = - is_potentially_variably_sized_type_v || is_potentially_variably_sized_type_v; + // True when either type is potentially variably sized (e.g. size_t, ptrdiff_t) + template + constexpr bool is_potentially_variably_sized_cast_v = + is_potentially_variably_sized_type_v || is_potentially_variably_sized_type_v; - // 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 = IntToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULongLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULongLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULongLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULongLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLongLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToULong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UInt8ToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToLong; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUInt; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToChar; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToShort; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToInt8; - template <> - __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToUChar; -} // namespace details -/// @endcond + // 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 = IntToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToInt8; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULongLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt8; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULongLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToInt8; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULongLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUShort; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULongLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULong; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUShort; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLongLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLong; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToShort; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt8; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUChar; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUInt; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToULong; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UInt8ToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUChar; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToLong; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt8; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUInt; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUShort; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToChar; + template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToShort; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToInt8; + template <> + __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToUChar; + } // namespace details + /// @endcond -// Unsafe conversion where failure results in fail fast. -template , int> = 0> -NewT safe_cast_failfast(const OldT var) -{ - NewT newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return newVar; -} + // Unsafe conversion where failure results in fail fast. + template , int> = 0> + NewT safe_cast_failfast(const OldT var) + { + NewT newVar; + FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return newVar; + } -// Unsafe conversion where failure results in fail fast. -template , int> = 0> -NewT safe_cast_failfast(const OldT var) -{ - NewT newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); - return newVar; -} + // Unsafe conversion where failure results in fail fast. + template , int> = 0> + NewT safe_cast_failfast(const OldT var) + { + NewT newVar; + FAIL_FAST_IF_FAILED( + (details::intsafe_conversion(static_cast(var), &newVar))); + return newVar; + } -// Unsafe conversion where failure results in fail fast. -template , int> = 0> -NewT safe_cast_failfast(const OldT var) -{ - unsigned short newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return static_cast<__wchar_t>(newVar); -} + // Unsafe conversion where failure results in fail fast. + template , int> = 0> + NewT safe_cast_failfast(const OldT var) + { + unsigned short newVar; + FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return static_cast<__wchar_t>(newVar); + } -// This conversion is always safe, therefore a static_cast is fine. -template , int> = 0> -NewT safe_cast_failfast(const OldT var) -{ - return static_cast(var); -} + // This conversion is always safe, therefore a static_cast is fine. + template , int> = 0> + NewT safe_cast_failfast(const OldT var) + { + return static_cast(var); + } #ifdef WIL_ENABLE_EXCEPTIONS -// Unsafe conversion where failure results in a thrown exception. -template , int> = 0> -NewT safe_cast(const OldT var) -{ - NewT newVar; - THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return newVar; -} + // Unsafe conversion where failure results in a thrown exception. + template , int> = 0> + NewT safe_cast(const OldT var) + { + NewT newVar; + THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return newVar; + } -// Unsafe conversion where failure results in a thrown exception. -template , int> = 0> -NewT safe_cast(const OldT var) -{ - NewT newVar; - THROW_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); - return newVar; -} + // Unsafe conversion where failure results in a thrown exception. + template , int> = 0> + NewT safe_cast(const OldT var) + { + NewT newVar; + THROW_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); + return newVar; + } -// Unsafe conversion where failure results in a thrown exception. -template , int> = 0> -NewT safe_cast(const OldT var) -{ - unsigned short newVar; - THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return static_cast<__wchar_t>(newVar); -} + // Unsafe conversion where failure results in a thrown exception. + template , int> = 0> + NewT safe_cast(const OldT var) + { + unsigned short newVar; + THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return static_cast<__wchar_t>(newVar); + } -// This conversion is always safe, therefore a static_cast is fine. -template , int> = 0> -NewT safe_cast(const OldT var) -{ - return static_cast(var); -} + // This conversion is always safe, therefore a static_cast is fine. + template , int> = 0> + NewT safe_cast(const OldT var) + { + return static_cast(var); + } #endif -// This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used -template , int> = 0> -NewT safe_cast_nothrow(const OldT /*var*/) -{ - static_assert(!wistd::is_same_v, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead"); -} + // This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used + template , int> = 0> + NewT safe_cast_nothrow(const OldT /*var*/) + { + static_assert(!wistd::is_same_v, + "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 , int> = 0> -NewT safe_cast_nothrow(const OldT var) -{ - return static_cast(var); -} + // This conversion is always safe, therefore a static_cast is fine. + template , int> = 0> + NewT safe_cast_nothrow(const OldT var) + { + return static_cast(var); + } -// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT -template , int> = 0> -HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) -{ - return details::intsafe_conversion(var, newTResult); -} + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template , int> = 0> + HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult) + { + return details::intsafe_conversion(var, newTResult); + } -// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT -template , int> = 0> -HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) -{ - return details::intsafe_conversion(static_cast(var), newTResult); -} + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template , int> = 0> + HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult) + { + return details::intsafe_conversion(static_cast(var), newTResult); + } -// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT -template , int> = 0> -HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) -{ - return details::intsafe_conversion(var, reinterpret_cast(newTResult)); -} + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template , int> = 0> + HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult) + { + return details::intsafe_conversion(var, reinterpret_cast(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 , int> = 0> -HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) -{ - static_assert( - details::is_potentially_variably_sized_cast_v, - "This cast is always safe; use safe_cast_nothrow(value) to avoid unnecessary error handling."); - *newTResult = static_cast(var); - return S_OK; -} + // 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 , int> = 0> + HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult) + { + static_assert(details::is_potentially_variably_sized_cast_v, + "This cast is always safe; use safe_cast_nothrow(value) to avoid unnecessary error handling."); + *newTResult = static_cast(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(-1) -// will return 0x00000000`FFFFFFFF on a 64-bit system. -template , 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; - return static_cast(static_cast(var)); -} + // 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(-1) + // will return 0x00000000`FFFFFFFF on a 64-bit system. + template , 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; + return static_cast(static_cast(var)); + } } // namespace wil #endif // __WIL_SAFECAST_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/stl.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/stl.h index e86ef88..5abaa4a 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/stl.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/stl.h @@ -17,8 +17,8 @@ #include "resource.h" #include #include -#include #include +#include #if (__WI_LIBCPP_STD_VER >= 17) && WI_HAS_INCLUDE(, 1) // Assume present if C++17 #include #endif @@ -33,196 +33,194 @@ 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 -struct secure_allocator : public std::allocator -{ - template - struct rebind + /** 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 struct secure_allocator : public std::allocator { - using other = secure_allocator; + template struct rebind + { + using other = secure_allocator; + }; + + secure_allocator() : std::allocator() + { + } + + ~secure_allocator() = default; + + secure_allocator(const secure_allocator &a) : std::allocator(a) + { + } + + template secure_allocator(const secure_allocator &a) : std::allocator(a) + { + } + + T *allocate(size_t n) + { + return std::allocator::allocate(n); + } + + void deallocate(T *p, size_t n) + { + SecureZeroMemory(p, sizeof(T) * n); + std::allocator::deallocate(p, n); + } }; - secure_allocator() : std::allocator() + //! `wil::secure_vector` will be securely zeroed before deallocation. + template using secure_vector = std::vector>; + //! `wil::secure_wstring` will be securely zeroed before deallocation. + using secure_wstring = std::basic_string, wil::secure_allocator>; + //! `wil::secure_string` will be securely zeroed before deallocation. + using secure_string = std::basic_string, wil::secure_allocator>; + + /// @cond + namespace details { + template <> struct string_maker + { + 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(); } - ~secure_allocator() = default; - - secure_allocator(const secure_allocator& a) : std::allocator(a) - { - } - - template - secure_allocator(const secure_allocator& a) : std::allocator(a) - { - } - - T* allocate(size_t n) - { - return std::allocator::allocate(n); - } - - void deallocate(T* p, size_t n) - { - SecureZeroMemory(p, sizeof(T) * n); - std::allocator::deallocate(p, n); - } -}; - -//! `wil::secure_vector` will be securely zeroed before deallocation. -template -using secure_vector = std::vector>; -//! `wil::secure_wstring` will be securely zeroed before deallocation. -using secure_wstring = std::basic_string, wil::secure_allocator>; -//! `wil::secure_string` will be securely zeroed before deallocation. -using secure_string = std::basic_string, wil::secure_allocator>; - -/// @cond -namespace details -{ - template <> - struct string_maker - { - 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 basic_zstring_view : public std::basic_string_view -{ - using size_type = typename std::basic_string_view::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(pStringData, stringLength) + /** + 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 basic_zstring_view : public std::basic_string_view { - if (pStringData[stringLength] != 0) + using size_type = typename std::basic_string_view::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(pStringData, stringLength) { - WI_STL_FAIL_FAST_IF(true); + if (pStringData[stringLength] != 0) + { + WI_STL_FAIL_FAST_IF(true); + } } - } - template - constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept : - std::basic_string_view(&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 ::value && !std::is_array::value>* = nullptr> - constexpr basic_zstring_view(TPtr&& pStr) noexcept : std::basic_string_view(std::forward(pStr)) - { - } - - constexpr basic_zstring_view(const std::basic_string& str) noexcept : - std::basic_string_view(&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 view(str, buf_size); - auto pos = view.find_first_of(TChar()); - if (pos == view.npos) + template + constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept + : std::basic_string_view(&stringArray[0], length_n(&stringArray[0], stringArrayLength)) { - 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::swap; - using std::basic_string_view::remove_suffix; -}; + // 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 ::value && + !std::is_array::value> * = nullptr> + constexpr basic_zstring_view(TPtr &&pStr) noexcept : std::basic_string_view(std::forward(pStr)) + { + } -using zstring_view = basic_zstring_view; -using zwstring_view = basic_zstring_view; + constexpr basic_zstring_view(const std::basic_string &str) noexcept + : std::basic_string_view(&str[0], str.size()) + { + } -inline namespace literals -{ - constexpr zstring_view operator""_zv(const char* str, std::size_t len) noexcept + // 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 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::swap; + using std::basic_string_view::remove_suffix; + }; + + using zstring_view = basic_zstring_view; + using zwstring_view = basic_zstring_view; + + inline namespace literals { - return zstring_view(str, len); - } + 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 + 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 diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/token_helpers.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/token_helpers.h index 468dc3a..382e77e 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/token_helpers.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/token_helpers.h @@ -18,8 +18,8 @@ #endif #include "resource.h" -#include #include // for UNLEN and DNLEN +#include #include // for GetUserNameEx() @@ -32,679 +32,675 @@ 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 - struct MapTokenStructToInfoClass; - template <> - struct MapTokenStructToInfoClass + /// @cond + namespace details { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOwner; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; - static constexpr bool FixedSize = false; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenUser; - static constexpr bool FixedSize = false; - }; - - // fixed size cases - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenSource; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenType; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; - static constexpr bool FixedSize = true; - }; - template <> - struct MapTokenStructToInfoClass - { - static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevation; - static constexpr bool FixedSize = true; - }; - - struct token_info_deleter - { - template - void operator()(T* p) const + // 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 struct MapTokenStructToInfoClass; + template <> struct MapTokenStructToInfoClass { - static_assert(wistd::is_trivially_destructible_v, "do not use with nontrivial types"); - ::operator delete(p); - } - }; -} // namespace details -/// @endcond + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOwner; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; + static constexpr bool FixedSize = false; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenUser; + static constexpr bool FixedSize = false; + }; -enum class OpenThreadTokenAs -{ - Current, - Self -}; + // fixed size cases + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenSource; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenType; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; + static constexpr bool FixedSize = true; + }; + template <> struct MapTokenStructToInfoClass + { + static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevation; + static constexpr bool FixedSize = true; + }; -/** 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. + struct token_info_deleter + { + template void operator()(T *p) const + { + static_assert(wistd::is_trivially_destructible_v, "do not use with nontrivial types"); + ::operator delete(p); + } + }; + } // namespace details + /// @endcond -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)) + enum class OpenThreadTokenAs { - hr = (OpenProcessToken(GetCurrentProcess(), access, tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError())); - } - return hr; -} + Current, + Self + }; -//! 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); -} + /** 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); -} + //! 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 (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 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 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 `` 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 -using unique_tokeninfo_ptr = wistd::unique_ptr; - -template ::FixedSize>* = nullptr> -inline HRESULT get_token_information_nothrow(unique_tokeninfo_ptr& tokenInfo, HANDLE tokenHandle = nullptr) -{ - tokenInfo.reset(); - tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); - - DWORD tokenInfoSize = 0; - const auto infoClass = details::MapTokenStructToInfoClass::infoClass; - RETURN_LAST_ERROR_IF( - !((!GetTokenInformation(tokenHandle, infoClass, nullptr, 0, &tokenInfoSize)) && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))); - unique_tokeninfo_ptr tokenInfoClose{static_cast(::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 ::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::infoClass; - RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfo, tokenInfoSize, &tokenInfoSize)); - - return S_OK; -} - -/// @cond -namespace details -{ - template ::FixedSize>* = nullptr> - unique_tokeninfo_ptr GetTokenInfoWrap(HANDLE token = nullptr) + // 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) { - unique_tokeninfo_ptr temp; - policy::HResult(get_token_information_nothrow(temp, token)); - return temp; + return tokenHandle ? tokenHandle : GetCurrentThreadEffectiveToken(); } - template ::FixedSize>* = nullptr> - T GetTokenInfoWrap(HANDLE token = nullptr) + /** 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 (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 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 privileges; + RETURN_IF_FAILED(wil::get_token_information_nothrow(privileges)); + for (auto const& privilege : wil::GetRange(privileges->Privileges, privileges->PrivilegeCount)) { - T temp{}; - policy::HResult(get_token_information_nothrow(&temp, token)); - return temp; + RETURN_IF_FAILED(ConsumePrivilege(privilege)); } -} // namespace details -/// @endcond + @endcode + @param tokenInfo Receives a pointer to a structure containing the results of GetTokenInformation for the requested + type. The type of `` 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. + */ -//! A variant of get_token_information that fails-fast on errors retrieving the token -template -inline auto get_token_information_failfast(HANDLE token = nullptr) -{ - return details::GetTokenInfoWrap(token); -} + template using unique_tokeninfo_ptr = wistd::unique_ptr; -//! 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); + template ::FixedSize> * = nullptr> + inline HRESULT get_token_information_nothrow(unique_tokeninfo_ptr &tokenInfo, HANDLE tokenHandle = nullptr) + { + tokenInfo.reset(); + tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); - DWORD tokenInfoSize = 0; - RETURN_IF_WIN32_BOOL_FALSE( - ::GetTokenInformation(tokenHandle, TokenLinkedToken, tokenInfo.reset_and_addressof(), sizeof(tokenInfo), &tokenInfoSize)); - return S_OK; -} + DWORD tokenInfoSize = 0; + const auto infoClass = details::MapTokenStructToInfoClass::infoClass; + RETURN_LAST_ERROR_IF(!((!GetTokenInformation(tokenHandle, infoClass, nullptr, 0, &tokenInfoSize)) && + (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))); + unique_tokeninfo_ptr tokenInfoClose{static_cast(::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); -/** 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(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; -} + return S_OK; + } + + template ::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::infoClass; + RETURN_IF_WIN32_BOOL_FALSE( + GetTokenInformation(tokenHandle, infoClass, tokenInfo, tokenInfoSize, &tokenInfoSize)); + + return S_OK; + } + + /// @cond + namespace details + { + template ::FixedSize> * = nullptr> + unique_tokeninfo_ptr GetTokenInfoWrap(HANDLE token = nullptr) + { + unique_tokeninfo_ptr temp; + policy::HResult(get_token_information_nothrow(temp, token)); + return temp; + } + + template ::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 that fails-fast on errors retrieving the token + template inline auto get_token_information_failfast(HANDLE token = nullptr) + { + return details::GetTokenInfoWrap(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(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(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(privileges); -for (auto& priv : wil::make_range(privs->Privileges, privs->Privilieges + privs->PrivilegeCount)) -{ - if (priv.Attributes & SE_PRIVILEGE_ENABLED) + /** Fetches information about a token. + See get_token_information_nothrow for full details. + @code + auto user = wil::get_token_information(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(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 + `` 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 inline auto get_token_information(HANDLE token = nullptr) + { + return details::GetTokenInfoWrap(token); } -} -@endcode -@return A pointer to a structure containing the results of GetTokenInformation for the requested type. The type of - `` 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 -inline auto get_token_information(HANDLE token = nullptr) -{ - return details::GetTokenInfoWrap(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(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; -} + /** 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(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) + /// @cond + namespace details { - FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken)); - - if (oldToken) + inline void RevertImpersonateToken(_In_ _Post_ptr_invalid_ HANDLE oldToken) { - ::CloseHandle(oldToken); + FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken)); + + if (oldToken) + { + ::CloseHandle(oldToken); + } } - } -} // namespace details -/// @endcond + } // namespace details + /// @endcond -using unique_token_reverter = - wil::unique_any; + using unique_token_reverter = + wil::unique_any; -/** 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, ¤tToken)) + /** 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) { - RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_NO_TOKEN); - } + wil::unique_handle userToken; + RETURN_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken)); - // 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_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; } - return S_OK; -} -~~~~ -*/ -inline HRESULT run_as_self_nothrow(unique_token_reverter& reverter) -{ - return impersonate_token_nothrow(nullptr, reverter); -} + ~~~~ + @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; -inline unique_token_reverter impersonate_token_failfast(HANDLE token) -{ - unique_token_reverter oldToken; - FAIL_FAST_IF_FAILED(impersonate_token_nothrow(token, oldToken)); - return oldToken; -} + // 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, ¤tToken)) + { + RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_NO_TOKEN); + } -inline unique_token_reverter run_as_self_failfast() -{ - return impersonate_token_failfast(nullptr); -} + // 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)) + /** 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) { - auto priorToken = wil::run_as_self(); - TakeOwnershipOfFile(filePath); - GrantDeleteAccess(filePath); - ::DeleteFile(filePath); + 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); } -} -~~~~ -*/ -inline unique_token_reverter run_as_self() -{ - return impersonate_token(nullptr); -} #endif // WIL_ENABLE_EXCEPTIONS -/// @cond -namespace details -{ - template - struct static_sid_t + /// @cond + namespace details { - BYTE Revision; - BYTE SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - DWORD SubAuthority[AuthorityCount]; - - PSID get() + template struct static_sid_t { - return reinterpret_cast(this); - } + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[AuthorityCount]; - template - static_sid_t& operator=(const static_sid_t& source) - { - static_assert(other <= AuthorityCount, "Cannot assign from a larger static sid to a smaller one"); - - if (&this->Revision != &source.Revision) + PSID get() { - memcpy(this, &source, sizeof(source)); + return reinterpret_cast(this); } - return *this; - } - }; -} // namespace details -/// @endcond + template static_sid_t &operator=(const static_sid_t &source) + { + static_assert(other <= AuthorityCount, "Cannot assign from a larger static sid to a smaller one"); -/** 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 -constexpr auto make_static_sid(const SID_IDENTIFIER_AUTHORITY& authority, Ts&&... subAuthorities) -{ - using sid_t = details::static_sid_t; + if (&this->Revision != &source.Revision) + { + memcpy(this, &source, sizeof(source)); + } - 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 *this; + } + }; + } // namespace details + /// @endcond - return sid_t{SID_REVISION, sizeof...(subAuthorities), authority, {static_cast(subAuthorities)...}}; -} + /** 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 + constexpr auto make_static_sid(const SID_IDENTIFIER_AUTHORITY &authority, Ts &&...subAuthorities) + { + using sid_t = details::static_sid_t; -//! Variant of static_sid that defaults to the NT authority -template -constexpr auto make_static_nt_sid(Ts&&... subAuthorities) -{ - return make_static_sid(SECURITY_NT_AUTHORITY, wistd::forward(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"); -/** 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 -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(subAuthorities)...); - BOOL isMember; - RETURN_IF_WIN32_BOOL_FALSE(CheckTokenMembership(token, &tempSid, &isMember)); + return sid_t{SID_REVISION, sizeof...(subAuthorities), authority, {static_cast(subAuthorities)...}}; + } - *result = (isMember != FALSE); + //! Variant of static_sid that defaults to the NT authority + template constexpr auto make_static_nt_sid(Ts &&...subAuthorities) + { + return make_static_sid(SECURITY_NT_AUTHORITY, wistd::forward(subAuthorities)...); + } - return S_OK; -} + /** 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 + 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(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)); + /** 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); + value = (isAppContainer != 0); - return S_OK; -} + 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)); + //! 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; -} + 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)); + //! 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; -} + return value; + } #endif // WIL_ENABLE_EXCEPTIONS #endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8 -template -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(subAuthorities)...)); - return result; -} + template + 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(subAuthorities)...)); + return result; + } #ifdef WIL_ENABLE_EXCEPTIONS -template -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(subAuthorities)...)); - return result; -} + template + 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(subAuthorities)...)); + return result; + } #endif } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_helpers.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_helpers.h index 53fd9ce..24ee444 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_helpers.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_helpers.h @@ -13,12 +13,12 @@ #ifndef __WIL_WIN32_HELPERS_INCLUDED #define __WIL_WIN32_HELPERS_INCLUDED -#include // FILETIME, HINSTANCE -#include // GetSystemTimeAsFileTime -#include // GetProcAddress #include // GetModuleFileNameExW (macro), K32GetModuleFileNameExW -#include +#include // GetProcAddress +#include // FILETIME, HINSTANCE #include +#include // GetSystemTimeAsFileTime +#include #include "common.h" @@ -45,8 +45,8 @@ #endif /// @endcond -#include "result.h" #include "resource.h" +#include "result.h" #include "wistd_functional.h" #include "wistd_type_traits.h" @@ -57,82 +57,82 @@ namespace wistd { #if WIL_USE_STL && (__cpp_lib_three_way_comparison >= 201907L) -using weak_ordering = std::weak_ordering; + using weak_ordering = std::weak_ordering; #else -struct weak_ordering -{ - static const weak_ordering less; - static const weak_ordering equivalent; - static const weak_ordering greater; - - [[nodiscard]] friend constexpr bool operator==(const weak_ordering left, std::nullptr_t) noexcept + struct weak_ordering { - return left.m_value == 0; - } + static const weak_ordering less; + static const weak_ordering equivalent; + static const weak_ordering greater; - [[nodiscard]] friend constexpr bool operator!=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value != 0; - } + [[nodiscard]] friend constexpr bool operator==(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value == 0; + } - [[nodiscard]] friend constexpr bool operator<(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value < 0; - } + [[nodiscard]] friend constexpr bool operator!=(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value != 0; + } - [[nodiscard]] friend constexpr bool operator>(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value > 0; - } + [[nodiscard]] friend constexpr bool operator<(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value < 0; + } - [[nodiscard]] friend constexpr bool operator<=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value <= 0; - } + [[nodiscard]] friend constexpr bool operator>(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value > 0; + } - [[nodiscard]] friend constexpr bool operator>=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value >= 0; - } + [[nodiscard]] friend constexpr bool operator<=(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value <= 0; + } - [[nodiscard]] friend constexpr bool operator==(std::nullptr_t, const weak_ordering right) noexcept - { - return right == 0; - } + [[nodiscard]] friend constexpr bool operator>=(const weak_ordering left, std::nullptr_t) noexcept + { + return left.m_value >= 0; + } - [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t, const weak_ordering right) noexcept - { - return right != 0; - } + [[nodiscard]] friend constexpr bool operator==(std::nullptr_t, const weak_ordering right) noexcept + { + return right == 0; + } - [[nodiscard]] friend constexpr bool operator<(std::nullptr_t, const weak_ordering right) noexcept - { - return right > 0; - } + [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t, const weak_ordering right) noexcept + { + return right != 0; + } - [[nodiscard]] friend constexpr bool operator>(std::nullptr_t, const weak_ordering right) noexcept - { - return right < 0; - } + [[nodiscard]] friend constexpr bool operator<(std::nullptr_t, const weak_ordering right) noexcept + { + return right > 0; + } - [[nodiscard]] friend constexpr bool operator<=(std::nullptr_t, const weak_ordering right) noexcept - { - return right >= 0; - } + [[nodiscard]] friend constexpr bool operator>(std::nullptr_t, const weak_ordering right) noexcept + { + return right < 0; + } - [[nodiscard]] friend constexpr bool operator>=(std::nullptr_t, const weak_ordering right) noexcept - { - return right <= 0; - } + [[nodiscard]] friend constexpr bool operator<=(std::nullptr_t, const weak_ordering right) noexcept + { + return right >= 0; + } - signed char m_value; -}; + [[nodiscard]] friend constexpr bool operator>=(std::nullptr_t, const weak_ordering right) noexcept + { + return right <= 0; + } -inline constexpr weak_ordering weak_ordering::less{static_cast(-1)}; -inline constexpr weak_ordering weak_ordering::equivalent{static_cast(0)}; -inline constexpr weak_ordering weak_ordering::greater{static_cast(1)}; + signed char m_value; + }; + + inline constexpr weak_ordering weak_ordering::less{static_cast(-1)}; + inline constexpr weak_ordering weak_ordering::equivalent{static_cast(0)}; + inline constexpr weak_ordering weak_ordering::greater{static_cast(1)}; #endif } // namespace wistd @@ -140,988 +140,1007 @@ inline constexpr weak_ordering weak_ordering::greater{static_cast(1 namespace wil { -//! Strictly a function of the file system but this is the value for all known file system, NTFS, FAT. -//! CDFs has a limit of 254. -constexpr size_t max_path_segment_length = 255; + //! Strictly a function of the file system but this is the value for all known file system, NTFS, FAT. + //! CDFs has a limit of 254. + constexpr size_t max_path_segment_length = 255; -//! Character length not including the null, MAX_PATH (260) includes the null. -constexpr size_t max_path_length = 259; + //! Character length not including the null, MAX_PATH (260) includes the null. + constexpr size_t max_path_length = 259; -//! 32743 Character length not including the null. This is a system defined limit. -//! The 24 is for the expansion of the roots from "C:" to "\Device\HarddiskVolume4" -//! It will be 25 when there are more than 9 disks. -constexpr size_t max_extended_path_length = 0x7FFF - 24; + //! 32743 Character length not including the null. This is a system defined limit. + //! The 24 is for the expansion of the roots from "C:" to "\Device\HarddiskVolume4" + //! It will be 25 when there are more than 9 disks. + constexpr size_t max_extended_path_length = 0x7FFF - 24; -//! For {guid} string form. Includes space for the null terminator. -constexpr size_t guid_string_buffer_length = 39; + //! For {guid} string form. Includes space for the null terminator. + constexpr size_t guid_string_buffer_length = 39; -//! For {guid} string form. Not including the null terminator. -constexpr size_t guid_string_length = 38; + //! For {guid} string form. Not including the null terminator. + constexpr size_t guid_string_length = 38; #pragma region String and identifier comparisons -// Using CompareStringOrdinal functions: -// -// Indentifiers require a locale-less (ordinal), and often case-insensitive, comparison (filenames, registry keys, XML node names, -// etc). DO NOT use locale-sensitive (lexical) comparisons for resource identifiers (e.g.wcs*() functions in the CRT). + // Using CompareStringOrdinal functions: + // + // Indentifiers require a locale-less (ordinal), and often case-insensitive, comparison (filenames, registry keys, + // XML node names, etc). DO NOT use locale-sensitive (lexical) comparisons for resource identifiers (e.g.wcs*() + // functions in the CRT). #if WIL_USE_STL && (__cpp_lib_string_view >= 201606L) -/// @cond -namespace details -{ - [[nodiscard]] inline int CompareStringOrdinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT + /// @cond + namespace details { - // Casting from size_t (unsigned) to int (signed) should be safe from overrun to a negative, - // merely truncating the string. CompareStringOrdinal should be resilient to negatives. - return ::CompareStringOrdinal( - left.data(), static_cast(left.size()), right.data(), static_cast(right.size()), caseInsensitive); - } -} // namespace details -/// @endcond + [[nodiscard]] inline int CompareStringOrdinal(std::wstring_view left, std::wstring_view right, + bool caseInsensitive) WI_NOEXCEPT + { + // Casting from size_t (unsigned) to int (signed) should be safe from overrun to a negative, + // merely truncating the string. CompareStringOrdinal should be resilient to negatives. + return ::CompareStringOrdinal(left.data(), static_cast(left.size()), right.data(), + static_cast(right.size()), caseInsensitive); + } + } // namespace details + /// @endcond -[[nodiscard]] inline wistd::weak_ordering compare_string_ordinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT -{ - switch (wil::details::CompareStringOrdinal(left, right, caseInsensitive)) + [[nodiscard]] inline wistd::weak_ordering compare_string_ordinal(std::wstring_view left, std::wstring_view right, + bool caseInsensitive) WI_NOEXCEPT { - case CSTR_LESS_THAN: - return wistd::weak_ordering::less; - case CSTR_GREATER_THAN: - return wistd::weak_ordering::greater; - default: - return wistd::weak_ordering::equivalent; + switch (wil::details::CompareStringOrdinal(left, right, caseInsensitive)) + { + case CSTR_LESS_THAN: + return wistd::weak_ordering::less; + case CSTR_GREATER_THAN: + return wistd::weak_ordering::greater; + default: + return wistd::weak_ordering::equivalent; + } } -} #endif #pragma endregion #pragma region FILETIME helpers -// FILETIME duration values. FILETIME is in 100 nanosecond units. -namespace filetime_duration -{ - long long const one_millisecond = 10000LL; - long long const one_second = 10000000LL; - long long const one_minute = 10000000LL * 60; // 600000000 or 600000000LL - long long const one_hour = 10000000LL * 60 * 60; // 36000000000 or 36000000000LL - long long const one_day = 10000000LL * 60 * 60 * 24; // 864000000000 or 864000000000LL -}; // namespace filetime_duration - -namespace filetime -{ - constexpr unsigned long long to_int64(const FILETIME& ft) WI_NOEXCEPT + // FILETIME duration values. FILETIME is in 100 nanosecond units. + namespace filetime_duration { + long long const one_millisecond = 10000LL; + long long const one_second = 10000000LL; + long long const one_minute = 10000000LL * 60; // 600000000 or 600000000LL + long long const one_hour = 10000000LL * 60 * 60; // 36000000000 or 36000000000LL + long long const one_day = 10000000LL * 60 * 60 * 24; // 864000000000 or 864000000000LL + }; // namespace filetime_duration + + namespace filetime + { + constexpr unsigned long long to_int64(const FILETIME &ft) WI_NOEXCEPT + { #if __cpp_lib_bit_cast >= 201806L - return std::bit_cast(ft); + return std::bit_cast(ft); #else - // Cannot reinterpret_cast FILETIME* to unsigned long long* - // due to alignment differences. - return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + // Cannot reinterpret_cast FILETIME* to unsigned long long* + // due to alignment differences. + return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; #endif - } + } - __WI_CONSTEXPR_BIT_CAST FILETIME from_int64(unsigned long long i64) WI_NOEXCEPT - { + __WI_CONSTEXPR_BIT_CAST FILETIME from_int64(unsigned long long i64) WI_NOEXCEPT + { #if __cpp_lib_bit_cast >= 201806L - return std::bit_cast(i64); + return std::bit_cast(i64); #else - static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match"); - static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), "alignment not compatible with type pun"); - return *reinterpret_cast(&i64); + static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match"); + static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), + "alignment not compatible with type pun"); + return *reinterpret_cast(&i64); #endif - } + } - __WI_CONSTEXPR_BIT_CAST FILETIME add(_In_ FILETIME const& ft, long long delta100ns) WI_NOEXCEPT - { - return from_int64(to_int64(ft) + delta100ns); - } + __WI_CONSTEXPR_BIT_CAST FILETIME add(_In_ FILETIME const &ft, long long delta100ns) WI_NOEXCEPT + { + return from_int64(to_int64(ft) + delta100ns); + } - constexpr bool is_empty(const FILETIME& ft) WI_NOEXCEPT - { - return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0); - } + constexpr bool is_empty(const FILETIME &ft) WI_NOEXCEPT + { + return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0); + } - inline FILETIME get_system_time() WI_NOEXCEPT - { - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return ft; - } + inline FILETIME get_system_time() WI_NOEXCEPT + { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return ft; + } - /// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated. - constexpr unsigned long long convert_100ns_to_msec(unsigned long long time100ns) WI_NOEXCEPT - { - return time100ns / filetime_duration::one_millisecond; - } + /// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated. + constexpr unsigned long long convert_100ns_to_msec(unsigned long long time100ns) WI_NOEXCEPT + { + return time100ns / filetime_duration::one_millisecond; + } - /// Convert time as milliseconds to units of 100 nanoseconds. - constexpr unsigned long long convert_msec_to_100ns(unsigned long long timeMsec) WI_NOEXCEPT - { - return timeMsec * filetime_duration::one_millisecond; - } + /// Convert time as milliseconds to units of 100 nanoseconds. + constexpr unsigned long long convert_msec_to_100ns(unsigned long long timeMsec) WI_NOEXCEPT + { + return timeMsec * filetime_duration::one_millisecond; + } #if (defined(_APISETREALTIME_) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7)) || defined(WIL_DOXYGEN) - /// Returns the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not - /// include time the system spends in sleep or hibernation. - /// - /// This API avoids prematurely shortcircuiting timing loops due to system sleep/hibernation. - /// - /// This is equivalent to GetTickCount64() except it returns units of 100 nanoseconds instead of milliseconds, and it doesn't - /// include time the system spends in sleep or hibernation. - /// For example - /// - /// start = GetTickCount64(); - /// hibernate(); - /// ...wake from hibernation 30 minutes later...; - /// elapsed = GetTickCount64() - start; - /// // elapsed = 30min - /// - /// Do the same using unbiased interrupt-time and elapsed is 0 (or nearly so). - /// - /// @note This is identical to QueryUnbiasedInterruptTime() but returns the value as a return value (rather than an out - /// parameter). - /// @see https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx - inline unsigned long long QueryUnbiasedInterruptTimeAs100ns() WI_NOEXCEPT - { - ULONGLONG now{}; - QueryUnbiasedInterruptTime(&now); - return now; - } + /// Returns the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time + /// count does not include time the system spends in sleep or hibernation. + /// + /// This API avoids prematurely shortcircuiting timing loops due to system sleep/hibernation. + /// + /// This is equivalent to GetTickCount64() except it returns units of 100 nanoseconds instead of milliseconds, + /// and it doesn't include time the system spends in sleep or hibernation. For example + /// + /// start = GetTickCount64(); + /// hibernate(); + /// ...wake from hibernation 30 minutes later...; + /// elapsed = GetTickCount64() - start; + /// // elapsed = 30min + /// + /// Do the same using unbiased interrupt-time and elapsed is 0 (or nearly so). + /// + /// @note This is identical to QueryUnbiasedInterruptTime() but returns the value as a return value (rather than + /// an out + /// parameter). + /// @see https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx + inline unsigned long long QueryUnbiasedInterruptTimeAs100ns() WI_NOEXCEPT + { + ULONGLONG now{}; + QueryUnbiasedInterruptTime(&now); + return now; + } - /// Returns the current unbiased interrupt-time count, in units of milliseconds. The unbiased interrupt-time count does not - /// include time the system spends in sleep or hibernation. - /// @see QueryUnbiasedInterruptTimeAs100ns - inline unsigned long long QueryUnbiasedInterruptTimeAsMSec() WI_NOEXCEPT - { - return convert_100ns_to_msec(QueryUnbiasedInterruptTimeAs100ns()); - } + /// Returns the current unbiased interrupt-time count, in units of milliseconds. The unbiased interrupt-time + /// count does not include time the system spends in sleep or hibernation. + /// @see QueryUnbiasedInterruptTimeAs100ns + inline unsigned long long QueryUnbiasedInterruptTimeAsMSec() WI_NOEXCEPT + { + return convert_100ns_to_msec(QueryUnbiasedInterruptTimeAs100ns()); + } #endif // _APISETREALTIME_ -} // namespace filetime + } // namespace filetime #pragma endregion #pragma region RECT helpers -template -constexpr auto rect_width(rect_type const& rect) -{ - return rect.right - rect.left; -} + template constexpr auto rect_width(rect_type const &rect) + { + return rect.right - rect.left; + } -template -constexpr auto rect_height(rect_type const& rect) -{ - return rect.bottom - rect.top; -} + template constexpr auto rect_height(rect_type const &rect) + { + return rect.bottom - rect.top; + } -template -constexpr auto rect_is_empty(rect_type const& rect) -{ - return (rect.left >= rect.right) || (rect.top >= rect.bottom); -} + template constexpr auto rect_is_empty(rect_type const &rect) + { + return (rect.left >= rect.right) || (rect.top >= rect.bottom); + } -template -constexpr auto rect_contains_point(rect_type const& rect, point_type const& point) -{ - return (point.x >= rect.left) && (point.x < rect.right) && (point.y >= rect.top) && (point.y < rect.bottom); -} + template + constexpr auto rect_contains_point(rect_type const &rect, point_type const &point) + { + return (point.x >= rect.left) && (point.x < rect.right) && (point.y >= rect.top) && (point.y < rect.bottom); + } -template -constexpr rect_type rect_from_size(length_type x, length_type y, length_type width, length_type height) -{ - rect_type rect; - rect.left = x; - rect.top = y; - rect.right = x + width; - rect.bottom = y + height; - return rect; -} + template + constexpr rect_type rect_from_size(length_type x, length_type y, length_type width, length_type height) + { + rect_type rect; + rect.left = x; + rect.top = y; + rect.right = x + width; + rect.bottom = y + height; + return rect; + } #pragma endregion -// Use to adapt Win32 APIs that take a fixed size buffer into forms that return -// an allocated buffer. Supports many types of string representation. -// See comments below on the expected behavior of the callback. -// Adjust stackBufferLength based on typical result sizes to optimize use and -// to test the boundary cases. -template -HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function callback) WI_NOEXCEPT -{ - details::string_maker maker; - - wchar_t value[stackBufferLength]{}; - size_t valueLengthNeededWithNull{}; // callback returns the number of characters needed including the null terminator. - RETURN_IF_FAILED_EXPECTED(callback(value, ARRAYSIZE(value), &valueLengthNeededWithNull)); - WI_ASSERT(valueLengthNeededWithNull > 0); - if (valueLengthNeededWithNull <= ARRAYSIZE(value)) + // Use to adapt Win32 APIs that take a fixed size buffer into forms that return + // an allocated buffer. Supports many types of string representation. + // See comments below on the expected behavior of the callback. + // Adjust stackBufferLength based on typical result sizes to optimize use and + // to test the boundary cases. + template + HRESULT AdaptFixedSizeToAllocatedResult(string_type &result, + wistd::function callback) WI_NOEXCEPT { - // Success case as described above, make() adds the space for the null. - RETURN_IF_FAILED(maker.make(value, valueLengthNeededWithNull - 1)); - } - else - { - // Did not fit in the stack allocated buffer, need to do 2 phase construction. - // May need to loop more than once if external conditions cause the value to change. - size_t bufferLength; - do + details::string_maker maker; + + wchar_t value[stackBufferLength]{}; + size_t valueLengthNeededWithNull{}; // callback returns the number of characters needed including the null + // terminator. + RETURN_IF_FAILED_EXPECTED(callback(value, ARRAYSIZE(value), &valueLengthNeededWithNull)); + WI_ASSERT(valueLengthNeededWithNull > 0); + if (valueLengthNeededWithNull <= ARRAYSIZE(value)) { - bufferLength = valueLengthNeededWithNull; - // bufferLength includes the null so subtract that as make() will add space for it. - RETURN_IF_FAILED(maker.make(nullptr, bufferLength - 1)); - - RETURN_IF_FAILED_EXPECTED(callback(maker.buffer(), bufferLength, &valueLengthNeededWithNull)); - WI_ASSERT(valueLengthNeededWithNull > 0); - - // If the value shrunk, then adjust the string to trim off the excess buffer. - if (valueLengthNeededWithNull < bufferLength) - { - RETURN_IF_FAILED(maker.trim_at_existing_null(valueLengthNeededWithNull - 1)); - } - } while (valueLengthNeededWithNull > bufferLength); - } - result = maker.release(); - return S_OK; -} - -/** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ -template -HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - *valueLengthNeededWithNul = ::ExpandEnvironmentStringsW(input, value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - return S_OK; - }); -} - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) -/** Searches for a specified file in a specified path using ExpandEnvironmentStringsW(); */ -template -HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - *valueLengthNeededWithNul = ::SearchPathW(path, fileName, extension, static_cast(valueLength), value, nullptr); - - if (*valueLengthNeededWithNul == 0) - { - // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW - const HRESULT searchResult = HRESULT_FROM_WIN32(::GetLastError()); - RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); - RETURN_IF_FAILED(searchResult); - } - - // AdaptFixedSizeToAllocatedResult expects that the length will always include the NUL. - // If the result is copied to the buffer, SearchPathW returns the length of copied string, WITHOUT the NUL. - // If the buffer is too small to hold the result, SearchPathW returns the length of the required buffer WITH the nul. - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // It fit, account for the null. - } - return S_OK; - }); -} - -template -HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - DWORD lengthToUse = static_cast(valueLength); - BOOL const success = ::QueryFullProcessImageNameW(processHandle, flags, value, &lengthToUse); - RETURN_LAST_ERROR_IF((success == FALSE) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)); - - // On success, return the amount used; on failure, try doubling - *valueLengthNeededWithNul = success ? (static_cast(lengthToUse) + 1) : (static_cast(lengthToUse) * 2); - return S_OK; - }); -} - -/** Expands environment strings and checks path existence with SearchPathW */ -template -HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT -{ - wil::unique_cotaskmem_string expandedName; - RETURN_IF_FAILED((wil::ExpandEnvironmentStringsW(input, expandedName))); - - // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW - const HRESULT searchResult = (wil::SearchPathW(nullptr, expandedName.get(), nullptr, result)); - RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); - RETURN_IF_FAILED(searchResult); - - return S_OK; -} -#endif - -/** Looks up the environment variable 'key' and fails if it is not found. */ -template -inline HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - // If the function succeeds, the return value is the number of characters stored in the buffer - // pointed to by lpBuffer, not including the terminating null character. - // - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in - // characters, required to hold the string and its terminating null character and the contents of - // lpBuffer are undefined. - // - // If the function fails, the return value is zero. If the specified environment variable was not - // found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND. - - ::SetLastError(ERROR_SUCCESS); - - *valueLengthNeededWithNul = ::GetEnvironmentVariableW(key, value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF_EXPECTED((*valueLengthNeededWithNul == 0) && (::GetLastError() != ERROR_SUCCESS)); - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // It fit, account for the null. - } - return S_OK; - }); -} - -/** Looks up the environment variable 'key' and returns null if it is not found. */ -template -HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT -{ - const auto hr = wil::GetEnvironmentVariableW(key, result); - RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND))); - return S_OK; -} - -/** Retrieves the fully qualified path for the file containing the specified module loaded -by a given process. Note GetModuleFileNameExW is a macro.*/ -template -HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path) WI_NOEXCEPT -{ - auto adapter = [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - DWORD copiedCount{}; - size_t valueUsedWithNul{}; - bool copyFailed{}; - bool copySucceededWithNoTruncation{}; - if (process != nullptr) - { - // GetModuleFileNameExW truncates and provides no error or other indication it has done so. - // The only way to be sure it didn't truncate is if it didn't need the whole buffer. The - // count copied to the buffer includes the nul-character as well. - copiedCount = ::GetModuleFileNameExW(process, module, value, static_cast(valueLength)); - valueUsedWithNul = static_cast(copiedCount) + 1; - copyFailed = (0 == copiedCount); - copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength - 1); + // Success case as described above, make() adds the space for the null. + RETURN_IF_FAILED(maker.make(value, valueLengthNeededWithNull - 1)); } else { - // In cases of insufficient buffer, GetModuleFileNameW will return a value equal to lengthWithNull - // and set the last error to ERROR_INSUFFICIENT_BUFFER. The count returned does not include - // the nul-character - copiedCount = ::GetModuleFileNameW(module, value, static_cast(valueLength)); - valueUsedWithNul = static_cast(copiedCount) + 1; - copyFailed = (0 == copiedCount); - copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength); - } - - RETURN_LAST_ERROR_IF(copyFailed); - - // When the copy truncated, request another try with more space. - *valueLengthNeededWithNul = copySucceededWithNoTruncation ? valueUsedWithNul : (valueLength * 2); - - return S_OK; - }; - - return wil::AdaptFixedSizeToAllocatedResult(path, wistd::move(adapter)); -} - -/** Retrieves the fully qualified path for the file that contains the specified module. -The module must have been loaded by the current process. The path returned will use the -same format that was specified when the module was loaded. Therefore, the path can be a -long or short file name, and can have the prefix '\\?\'. */ -template -HRESULT GetModuleFileNameW(HMODULE module, string_type& path) WI_NOEXCEPT -{ - return wil::GetModuleFileNameExW(nullptr, module, path); -} - -template -HRESULT GetSystemDirectoryW(string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - *valueLengthNeededWithNul = ::GetSystemDirectoryW(value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - if (*valueLengthNeededWithNul < valueLength) + // Did not fit in the stack allocated buffer, need to do 2 phase construction. + // May need to loop more than once if external conditions cause the value to change. + size_t bufferLength; + do { - (*valueLengthNeededWithNul)++; // it fit, account for the null - } - return S_OK; - }); -} + bufferLength = valueLengthNeededWithNull; + // bufferLength includes the null so subtract that as make() will add space for it. + RETURN_IF_FAILED(maker.make(nullptr, bufferLength - 1)); + + RETURN_IF_FAILED_EXPECTED(callback(maker.buffer(), bufferLength, &valueLengthNeededWithNull)); + WI_ASSERT(valueLengthNeededWithNull > 0); + + // If the value shrunk, then adjust the string to trim off the excess buffer. + if (valueLengthNeededWithNull < bufferLength) + { + RETURN_IF_FAILED(maker.trim_at_existing_null(valueLengthNeededWithNull - 1)); + } + } while (valueLengthNeededWithNull > bufferLength); + } + result = maker.release(); + return S_OK; + } + + /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ + template + HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + *valueLengthNeededWithNul = ::ExpandEnvironmentStringsW(input, value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); + return S_OK; + }); + } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) -template -HRESULT GetWindowsDirectoryW(string_type& result) WI_NOEXCEPT -{ - return wil::AdaptFixedSizeToAllocatedResult( - result, [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT { - *valueLengthNeededWithNul = ::GetWindowsDirectoryW(value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - if (*valueLengthNeededWithNul < valueLength) + /** Searches for a specified file in a specified path using ExpandEnvironmentStringsW(); */ + template + HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, + string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + *valueLengthNeededWithNul = + ::SearchPathW(path, fileName, extension, static_cast(valueLength), value, nullptr); + + if (*valueLengthNeededWithNul == 0) + { + // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW + const HRESULT searchResult = HRESULT_FROM_WIN32(::GetLastError()); + RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + RETURN_IF_FAILED(searchResult); + } + + // AdaptFixedSizeToAllocatedResult expects that the length will always include the NUL. + // If the result is copied to the buffer, SearchPathW returns the length of copied string, WITHOUT the + // NUL. If the buffer is too small to hold the result, SearchPathW returns the length of the required + // buffer WITH the nul. + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // It fit, account for the null. + } + return S_OK; + }); + } + + template + HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + DWORD lengthToUse = static_cast(valueLength); + BOOL const success = ::QueryFullProcessImageNameW(processHandle, flags, value, &lengthToUse); + RETURN_LAST_ERROR_IF((success == FALSE) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)); + + // On success, return the amount used; on failure, try doubling + *valueLengthNeededWithNul = + success ? (static_cast(lengthToUse) + 1) : (static_cast(lengthToUse) * 2); + return S_OK; + }); + } + + /** Expands environment strings and checks path existence with SearchPathW */ + template + HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type &result) WI_NOEXCEPT + { + wil::unique_cotaskmem_string expandedName; + RETURN_IF_FAILED((wil::ExpandEnvironmentStringsW(input, expandedName))); + + // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW + const HRESULT searchResult = + (wil::SearchPathW(nullptr, expandedName.get(), nullptr, result)); + RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + RETURN_IF_FAILED(searchResult); + + return S_OK; + } +#endif + + /** Looks up the environment variable 'key' and fails if it is not found. */ + template + inline HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + // If the function succeeds, the return value is the number of characters stored in the buffer + // pointed to by lpBuffer, not including the terminating null character. + // + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in + // characters, required to hold the string and its terminating null character and the contents of + // lpBuffer are undefined. + // + // If the function fails, the return value is zero. If the specified environment variable was not + // found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND. + + ::SetLastError(ERROR_SUCCESS); + + *valueLengthNeededWithNul = ::GetEnvironmentVariableW(key, value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF_EXPECTED((*valueLengthNeededWithNul == 0) && (::GetLastError() != ERROR_SUCCESS)); + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // It fit, account for the null. + } + return S_OK; + }); + } + + /** Looks up the environment variable 'key' and returns null if it is not found. */ + template + HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type &result) WI_NOEXCEPT + { + const auto hr = wil::GetEnvironmentVariableW(key, result); + RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND))); + return S_OK; + } + + /** Retrieves the fully qualified path for the file containing the specified module loaded + by a given process. Note GetModuleFileNameExW is a macro.*/ + template + HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type &path) WI_NOEXCEPT + { + auto adapter = [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + DWORD copiedCount{}; + size_t valueUsedWithNul{}; + bool copyFailed{}; + bool copySucceededWithNoTruncation{}; + if (process != nullptr) { - (*valueLengthNeededWithNul)++; // it fit, account for the null + // GetModuleFileNameExW truncates and provides no error or other indication it has done so. + // The only way to be sure it didn't truncate is if it didn't need the whole buffer. The + // count copied to the buffer includes the nul-character as well. + copiedCount = ::GetModuleFileNameExW(process, module, value, static_cast(valueLength)); + valueUsedWithNul = static_cast(copiedCount) + 1; + copyFailed = (0 == copiedCount); + copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength - 1); } + else + { + // In cases of insufficient buffer, GetModuleFileNameW will return a value equal to lengthWithNull + // and set the last error to ERROR_INSUFFICIENT_BUFFER. The count returned does not include + // the nul-character + copiedCount = ::GetModuleFileNameW(module, value, static_cast(valueLength)); + valueUsedWithNul = static_cast(copiedCount) + 1; + copyFailed = (0 == copiedCount); + copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength); + } + + RETURN_LAST_ERROR_IF(copyFailed); + + // When the copy truncated, request another try with more space. + *valueLengthNeededWithNul = copySucceededWithNoTruncation ? valueUsedWithNul : (valueLength * 2); + return S_OK; - }); -} + }; + + return wil::AdaptFixedSizeToAllocatedResult(path, wistd::move(adapter)); + } + + /** Retrieves the fully qualified path for the file that contains the specified module. + The module must have been loaded by the current process. The path returned will use the + same format that was specified when the module was loaded. Therefore, the path can be a + long or short file name, and can have the prefix '\\?\'. */ + template + HRESULT GetModuleFileNameW(HMODULE module, string_type &path) WI_NOEXCEPT + { + return wil::GetModuleFileNameExW(nullptr, module, path); + } + + template + HRESULT GetSystemDirectoryW(string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + *valueLengthNeededWithNul = ::GetSystemDirectoryW(value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // it fit, account for the null + } + return S_OK; + }); + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) + template + HRESULT GetWindowsDirectoryW(string_type &result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult( + result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, + _Out_ size_t *valueLengthNeededWithNul) -> HRESULT { + *valueLengthNeededWithNul = ::GetWindowsDirectoryW(value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // it fit, account for the null + } + return S_OK; + }); + } #endif #ifdef WIL_ENABLE_EXCEPTIONS -/** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ -template -string_type ExpandEnvironmentStringsW(_In_ PCWSTR input) -{ - string_type result{}; - THROW_IF_FAILED((wil::ExpandEnvironmentStringsW(input, result))); - return result; -} + /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ + template + string_type ExpandEnvironmentStringsW(_In_ PCWSTR input) + { + string_type result{}; + THROW_IF_FAILED((wil::ExpandEnvironmentStringsW(input, result))); + return result; + } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) -/** Searches for a specified file in a specified path using SearchPathW*/ -template -string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension) -{ - string_type result{}; - HRESULT searchHR = wil::SearchPathW(path, fileName, extension, result); - THROW_HR_IF(searchHR, FAILED(searchHR) && (searchHR != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))); - return result; -} + /** Searches for a specified file in a specified path using SearchPathW*/ + template + string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension) + { + string_type result{}; + HRESULT searchHR = wil::SearchPathW(path, fileName, extension, result); + THROW_HR_IF(searchHR, FAILED(searchHR) && (searchHR != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))); + return result; + } #endif -/** Looks up the environment variable 'key' and fails if it is not found. */ -template -string_type GetEnvironmentVariableW(_In_ PCWSTR key) -{ - string_type result{}; - THROW_IF_FAILED((wil::GetEnvironmentVariableW(key, result))); - return result; -} + /** Looks up the environment variable 'key' and fails if it is not found. */ + template + string_type GetEnvironmentVariableW(_In_ PCWSTR key) + { + string_type result{}; + THROW_IF_FAILED((wil::GetEnvironmentVariableW(key, result))); + return result; + } -/** Looks up the environment variable 'key' and returns null if it is not found. */ -template -string_type TryGetEnvironmentVariableW(_In_ PCWSTR key) -{ - string_type result{}; - THROW_IF_FAILED((wil::TryGetEnvironmentVariableW(key, result))); - return result; -} + /** Looks up the environment variable 'key' and returns null if it is not found. */ + template + string_type TryGetEnvironmentVariableW(_In_ PCWSTR key) + { + string_type result{}; + THROW_IF_FAILED((wil::TryGetEnvironmentVariableW(key, result))); + return result; + } -template -string_type GetModuleFileNameW(HMODULE module = nullptr /* current process module */) -{ - string_type result{}; - THROW_IF_FAILED((wil::GetModuleFileNameW(module, result))); - return result; -} + template + string_type GetModuleFileNameW(HMODULE module = nullptr /* current process module */) + { + string_type result{}; + THROW_IF_FAILED((wil::GetModuleFileNameW(module, result))); + return result; + } -template -string_type GetModuleFileNameExW(HANDLE process, HMODULE module) -{ - string_type result{}; - THROW_IF_FAILED((wil::GetModuleFileNameExW(process, module, result))); - return result; -} + template + string_type GetModuleFileNameExW(HANDLE process, HMODULE module) + { + string_type result{}; + THROW_IF_FAILED((wil::GetModuleFileNameExW(process, module, result))); + return result; + } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) -template -string_type GetWindowsDirectoryW() -{ - string_type result; - THROW_IF_FAILED((wil::GetWindowsDirectoryW(result))); - return result; -} + template + string_type GetWindowsDirectoryW() + { + string_type result; + THROW_IF_FAILED((wil::GetWindowsDirectoryW(result))); + return result; + } #endif -template -string_type GetSystemDirectoryW() -{ - string_type result; - THROW_IF_FAILED((wil::GetSystemDirectoryW(result))); - return result; -} + template + string_type GetSystemDirectoryW() + { + string_type result; + THROW_IF_FAILED((wil::GetSystemDirectoryW(result))); + return result; + } -template -string_type QueryFullProcessImageNameW(HANDLE processHandle = GetCurrentProcess(), DWORD flags = 0) -{ - string_type result{}; - THROW_IF_FAILED((wil::QueryFullProcessImageNameW(processHandle, flags, result))); - return result; -} + template + string_type QueryFullProcessImageNameW(HANDLE processHandle = GetCurrentProcess(), DWORD flags = 0) + { + string_type result{}; + THROW_IF_FAILED( + (wil::QueryFullProcessImageNameW(processHandle, flags, result))); + return result; + } #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -// Lookup a DWORD value under HKLM\...\Image File Execution Options\ -inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultValue = 0) -{ - auto filePath = wil::GetModuleFileNameW(); - if (auto lastSlash = wcsrchr(filePath.get(), L'\\')) + // Lookup a DWORD value under HKLM\...\Image File Execution Options\ + inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultValue = 0) { - const auto fileName = lastSlash + 1; - auto keyPath = wil::str_concat( - LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)", fileName); - DWORD value{}, sizeofValue = sizeof(value); - if (::RegGetValueW( - HKEY_LOCAL_MACHINE, - keyPath.get(), - valueName, -#ifdef RRF_SUBKEY_WOW6464KEY - RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, -#else - RRF_RT_REG_DWORD, -#endif - nullptr, - &value, - &sizeofValue) == ERROR_SUCCESS) + auto filePath = wil::GetModuleFileNameW(); + if (auto lastSlash = wcsrchr(filePath.get(), L'\\')) { - return value; + const auto fileName = lastSlash + 1; + auto keyPath = wil::str_concat( + LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)", fileName); + DWORD value{}, sizeofValue = sizeof(value); + if (::RegGetValueW(HKEY_LOCAL_MACHINE, keyPath.get(), valueName, +#ifdef RRF_SUBKEY_WOW6464KEY + RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, +#else + RRF_RT_REG_DWORD, +#endif + nullptr, &value, &sizeofValue) == ERROR_SUCCESS) + { + return value; + } } + return defaultValue; } - return defaultValue; -} #ifndef DebugBreak // Some code defines 'DebugBreak' to garbage to force build breaks in release builds -// Waits for a debugger to attach to the current process based on registry configuration. -// -// Example: -// HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe -// WaitForDebuggerPresent=1 -// -// REG_DWORD value of -// missing or 0 -> don't break -// 1 -> wait for the debugger, continue execution once it is attached -// 2 -> wait for the debugger, break here once attached. -inline void WaitForDebuggerPresent(bool checkRegistryConfig = true) -{ - for (;;) + // Waits for a debugger to attach to the current process based on registry configuration. + // + // Example: + // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe + // WaitForDebuggerPresent=1 + // + // REG_DWORD value of + // missing or 0 -> don't break + // 1 -> wait for the debugger, continue execution once it is attached + // 2 -> wait for the debugger, break here once attached. + inline void WaitForDebuggerPresent(bool checkRegistryConfig = true) { - auto configValue = checkRegistryConfig ? GetCurrentProcessExecutionOption(L"WaitForDebuggerPresent") : 1; - if (configValue == 0) + for (;;) { - return; // not configured, don't wait - } - - if (IsDebuggerPresent()) - { - if (configValue == 2) + auto configValue = checkRegistryConfig ? GetCurrentProcessExecutionOption(L"WaitForDebuggerPresent") : 1; + if (configValue == 0) { - DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller + return; // not configured, don't wait } - return; // debugger now attached, continue executing + + if (IsDebuggerPresent()) + { + if (configValue == 2) + { + DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller + } + return; // debugger now attached, continue executing + } + Sleep(500); } - Sleep(500); } -} #endif #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) #endif -/** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that -the linker provides for every module. This avoids the need for a global HINSTANCE variable -and provides access to this value for static libraries. */ -inline HINSTANCE GetModuleInstanceHandle() WI_NOEXCEPT -{ - return reinterpret_cast(&__ImageBase); -} + /** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that + the linker provides for every module. This avoids the need for a global HINSTANCE variable + and provides access to this value for static libraries. */ + inline HINSTANCE GetModuleInstanceHandle() WI_NOEXCEPT + { + return reinterpret_cast(&__ImageBase); + } // GetModuleHandleExW was added to the app partition in version 22000 of the SDK -#if defined(NTDDI_WIN10_CO) ? WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) \ - : WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) -// Use this in threads that can outlive the object or API call that created them. -// Without this COM, or the API caller, can unload the DLL, resulting in a crash. -// It is very important that this be the first object created in the thread proc -// as when this runs down the thread exits and no destructors of objects created before -// it will run. -[[nodiscard]] inline auto get_module_reference_for_thread() noexcept -{ - HMODULE thisModule{}; - FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, L"", &thisModule)); - return wil::scope_exit([thisModule] { - FreeLibraryAndExitThread(thisModule, 0); - }); -} +#if defined(NTDDI_WIN10_CO) \ + ? WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) \ + : WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) + // Use this in threads that can outlive the object or API call that created them. + // Without this COM, or the API caller, can unload the DLL, resulting in a crash. + // It is very important that this be the first object created in the thread proc + // as when this runs down the thread exits and no destructors of objects created before + // it will run. + [[nodiscard]] inline auto get_module_reference_for_thread() noexcept + { + HMODULE thisModule{}; + FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, L"", &thisModule)); + return wil::scope_exit([thisModule] { FreeLibraryAndExitThread(thisModule, 0); }); + } #endif -/// @cond -namespace details -{ - class init_once_completer + /// @cond + namespace details { - INIT_ONCE& m_once; - unsigned long m_flags = INIT_ONCE_INIT_FAILED; - - public: - init_once_completer(_In_ INIT_ONCE& once) WI_NOEXCEPT : m_once(once) + class init_once_completer { - } + INIT_ONCE &m_once; + unsigned long m_flags = INIT_ONCE_INIT_FAILED; + + public: + init_once_completer(_In_ INIT_ONCE &once) WI_NOEXCEPT : m_once(once) + { + } #pragma warning(push) #pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2 - void success() WI_NOEXCEPT - { - m_flags = 0; - } + void success() WI_NOEXCEPT + { + m_flags = 0; + } #pragma warning(pop) - ~init_once_completer() WI_NOEXCEPT + ~init_once_completer() WI_NOEXCEPT + { + ::InitOnceComplete(&m_once, m_flags, nullptr); + } + }; + } // namespace details + /// @endcond + + /** Performs one-time initialization + Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked + at most once. + ~~~~ + INIT_ONCE g_init{}; + ComPtr g_foo; + HRESULT MyMethod() + { + bool winner = false; + RETURN_IF_FAILED(wil::init_once_nothrow(g_init, [] { - ::InitOnceComplete(&m_once, m_flags, nullptr); + ComPtr foo; + RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); + RETURN_IF_FAILED(foo->Startup()); + g_foo = foo; + }, &winner); + if (winner) + { + RETURN_IF_FAILED(g_foo->Another()); } + return S_OK; + } + ~~~~ + See MSDN for more information on `InitOnceExecuteOnce`. + @param initOnce The INIT_ONCE structure to use as context for initialization. + @param func A function that will be invoked to perform initialization. If this fails, the init call + fails and the once-init is not marked as initialized. A later caller could attempt to + initialize it a second time. + @param callerCompleted Set to 'true' if this was the call that caused initialization, false otherwise. + */ + template + HRESULT init_once_nothrow(_Inout_ INIT_ONCE &initOnce, T func, + _Out_opt_ bool *callerCompleted = nullptr) WI_NOEXCEPT + { + BOOL pending = FALSE; + wil::assign_to_opt_param(callerCompleted, false); + + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); + + if (pending) + { + details::init_once_completer completion(initOnce); + __WIL_PRIVATE_RETURN_IF_FAILED(func()); + completion.success(); + wil::assign_to_opt_param(callerCompleted, true); + } + + return S_OK; + } + + //! Similar to init_once_nothrow, but fails-fast if the initialization step failed. The 'callerComplete' value is + //! returned to the caller instead of being an out-parameter. + template bool init_once_failfast(_Inout_ INIT_ONCE &initOnce, T &&func) WI_NOEXCEPT + { + bool callerCompleted; + + FAIL_FAST_IF_FAILED(init_once_nothrow(initOnce, wistd::forward(func), &callerCompleted)); + + return callerCompleted; }; -} // namespace details -/// @endcond -/** Performs one-time initialization -Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked -at most once. -~~~~ -INIT_ONCE g_init{}; -ComPtr g_foo; -HRESULT MyMethod() -{ - bool winner = false; - RETURN_IF_FAILED(wil::init_once_nothrow(g_init, [] + //! Returns 'true' if this `init_once` structure has finished initialization, false otherwise. + inline bool init_once_initialized(_Inout_ INIT_ONCE &initOnce) WI_NOEXCEPT { - ComPtr foo; - RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); - RETURN_IF_FAILED(foo->Startup()); - g_foo = foo; - }, &winner); - if (winner) - { - RETURN_IF_FAILED(g_foo->Another()); + BOOL pending = FALSE; + return ::InitOnceBeginInitialize(&initOnce, INIT_ONCE_CHECK_ONLY, &pending, nullptr) && !pending; } - return S_OK; -} -~~~~ -See MSDN for more information on `InitOnceExecuteOnce`. -@param initOnce The INIT_ONCE structure to use as context for initialization. -@param func A function that will be invoked to perform initialization. If this fails, the init call - fails and the once-init is not marked as initialized. A later caller could attempt to - initialize it a second time. -@param callerCompleted Set to 'true' if this was the call that caused initialization, false otherwise. -*/ -template -HRESULT init_once_nothrow(_Inout_ INIT_ONCE& initOnce, T func, _Out_opt_ bool* callerCompleted = nullptr) WI_NOEXCEPT -{ - BOOL pending = FALSE; - wil::assign_to_opt_param(callerCompleted, false); - - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); - - if (pending) - { - details::init_once_completer completion(initOnce); - __WIL_PRIVATE_RETURN_IF_FAILED(func()); - completion.success(); - wil::assign_to_opt_param(callerCompleted, true); - } - - return S_OK; -} - -//! Similar to init_once_nothrow, but fails-fast if the initialization step failed. The 'callerComplete' value is -//! returned to the caller instead of being an out-parameter. -template -bool init_once_failfast(_Inout_ INIT_ONCE& initOnce, T&& func) WI_NOEXCEPT -{ - bool callerCompleted; - - FAIL_FAST_IF_FAILED(init_once_nothrow(initOnce, wistd::forward(func), &callerCompleted)); - - return callerCompleted; -}; - -//! Returns 'true' if this `init_once` structure has finished initialization, false otherwise. -inline bool init_once_initialized(_Inout_ INIT_ONCE& initOnce) WI_NOEXCEPT -{ - BOOL pending = FALSE; - return ::InitOnceBeginInitialize(&initOnce, INIT_ONCE_CHECK_ONLY, &pending, nullptr) && !pending; -} #ifdef WIL_ENABLE_EXCEPTIONS -/** Performs one-time initialization -Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked -at most once. -~~~~ -INIT_ONCE g_init{}; -ComPtr g_foo; -void MyMethod() -{ - bool winner = wil::init_once(g_init, [] + /** Performs one-time initialization + Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked + at most once. + ~~~~ + INIT_ONCE g_init{}; + ComPtr g_foo; + void MyMethod() { - ComPtr foo; - THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); - THROW_IF_FAILED(foo->Startup()); - g_foo = foo; - }); - if (winner) - { - THROW_IF_FAILED(g_foo->Another()); + bool winner = wil::init_once(g_init, [] + { + ComPtr foo; + THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); + THROW_IF_FAILED(foo->Startup()); + g_foo = foo; + }); + if (winner) + { + THROW_IF_FAILED(g_foo->Another()); + } } -} -~~~~ -See MSDN for more information on `InitOnceExecuteOnce`. -@param initOnce The INIT_ONCE structure to use as context for initialization. -@param func A function that will be invoked to perform initialization. If this fails, the init call - fails and the once-init is not marked as initialized. A later caller could attempt to - initialize it a second time. -@returns 'true' if this was the call that caused initialization, false otherwise. -*/ -template -bool init_once(_Inout_ INIT_ONCE& initOnce, T func) -{ - BOOL pending = FALSE; + ~~~~ + See MSDN for more information on `InitOnceExecuteOnce`. + @param initOnce The INIT_ONCE structure to use as context for initialization. + @param func A function that will be invoked to perform initialization. If this fails, the init call + fails and the once-init is not marked as initialized. A later caller could attempt to + initialize it a second time. + @returns 'true' if this was the call that caused initialization, false otherwise. + */ + template bool init_once(_Inout_ INIT_ONCE &initOnce, T func) + { + BOOL pending = FALSE; - THROW_IF_WIN32_BOOL_FALSE(::InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); + THROW_IF_WIN32_BOOL_FALSE(::InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); - if (pending) - { - details::init_once_completer completion(initOnce); - func(); - completion.success(); - return true; + if (pending) + { + details::init_once_completer completion(initOnce); + func(); + completion.success(); + return true; + } + else + { + return false; + } } - else - { - return false; - } -} #endif // WIL_ENABLE_EXCEPTIONS #if WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS) && (__cpp_lib_string_view >= 201606L) -/// @cond -namespace details -{ - template - struct deduce_char_type_from_string_range + /// @cond + namespace details { - template - static auto deduce(T& range) + template struct deduce_char_type_from_string_range { - using std::begin; - return (*begin(range))[0]; - } - - using type = decltype(deduce(wistd::declval())); - }; - - template - using deduce_char_type_from_string_range_t = typename deduce_char_type_from_string_range::type; - - // Internal helper span-like type for passing arrays as an iterable collection - template - struct iterable_span - { - T* pointer; - size_t size; - - constexpr T* begin() const noexcept - { - return pointer; - } - - constexpr T* end() const noexcept - { - return pointer + size; - } - }; -} // namespace details -/// @endcond - -//! Flags that control the behavior of `ArgvToCommandLine` -enum class ArgvToCommandLineFlags : uint8_t -{ - None = 0, - - //! By default, arguments are only surrounded by quotes when necessary (i.e. the argument contains a space). When - //! this flag is specified, all arguments are surrounded with quotes, regardless of whether or not they contain - //! space(s). This is an optimization as it means that we are not required to search for spaces in each argument and - //! we don't need to potentially go back and insert a quotation character in the middle of the string after we've - //! already written part of the argument to the result. That said, wrapping all arguments with quotes can have some - //! adverse effects with some applications, most notably cmd.exe, which do their own command line processing. - ForceQuotes = 0x01 << 0, - - //! `CommandLineToArgvW` has an "optimization" that assumes that the first argument is the path to an executable. - //! Because valid NTFS paths cannot contain quotation characters, `CommandLineToArgvW` disables its quote escaping - //! logic for the first argument. By default, `ArgvToCommandLine` aims to ensure that an argv array can "round trip" - //! to a string and back, meaning it tries to replicate this logic in reverse. This flag disables this logic and - //! escapes backslashes and quotes the same for all arguments, including the first one. This is useful if the output - //! string is only an intermediate command line string (e.g. if the executable path is prepended later). - FirstArgumentIsNotPath = 0x01 << 1, -}; -DEFINE_ENUM_FLAG_OPERATORS(ArgvToCommandLineFlags); - -//! Performs the reverse operation of CommandLineToArgvW. -//! Converts an argv array to a command line string that is guaranteed to "round trip" with CommandLineToArgvW. That is, -//! a call to wil::ArgvToCommandLine followed by a call to ArgvToCommandLineW will produce the same array that was -//! passed to wil::ArgvToCommandLine. Note that the reverse is not true. I.e. calling ArgvToCommandLineW followed by -//! wil::ArgvToCommandLine will not produce the original string due to the optionality of of quotes in the command line -//! string. This functionality is useful in a number of scenarios, most notably: -//! 1. When implementing a "driver" application. That is, an application that consumes some command line arguments, -//! translates others into new arguments, and preserves the rest, "forwarding" the resulting command line to a -//! separate application. -//! 2. When reading command line arguments from some data storage, e.g. from a JSON array, which then need to get -//! compiled into a command line string that's used for creating a new process. -//! Unlike CommandLineToArgvW, this function accepts both "narrow" and "wide" strings to support calling both -//! CreateProcessW and CreateProcessA with the result. See the values in @ref wil::ArgvToCommandLineFlags for more -//! information on how to control the behavior of this function as well as scenarios when you may want to use each one. -template > -inline std::basic_string ArgvToCommandLine(RangeT&& range, ArgvToCommandLineFlags flags = ArgvToCommandLineFlags::None) -{ - using string_type = std::basic_string; - using string_view_type = std::basic_string_view; - - // Somewhat of a hack to avoid the fact that we can't conditionalize a string literal on a template - static constexpr const CharT empty_string[] = {'\0'}; - static constexpr const CharT single_quote_string[] = {'"', '\0'}; - static constexpr const CharT space_string[] = {' ', '\0'}; - static constexpr const CharT quoted_space_string[] = {'"', ' ', '"', '\0'}; - - static constexpr const CharT search_string_no_space[] = {'\\', '"', '\0'}; - static constexpr const CharT search_string_with_space[] = {'\\', '"', ' ', '\t', '\0'}; - - const bool forceQuotes = WI_IsFlagSet(flags, ArgvToCommandLineFlags::ForceQuotes); - const CharT* const initialSearchString = forceQuotes ? search_string_no_space : search_string_with_space; - const CharT* prefix = forceQuotes ? single_quote_string : empty_string; - const CharT* const nextPrefix = forceQuotes ? quoted_space_string : space_string; - - string_type result; - int index = 0; - for (auto&& strRaw : range) - { - auto currentIndex = index++; - result += prefix; - - const CharT* searchString = initialSearchString; - - // Info just in case we need to come back and insert quotes - auto startPos = result.size(); - bool terminateWithQuotes = false; // With forceQuotes == true, this is baked into the prefix - - // We need to escape any quotes and CONDITIONALLY any backslashes - string_view_type str(strRaw); - size_t pos = 0; - while (pos < str.size()) - { - auto nextPos = str.find_first_of(searchString, pos); - if ((nextPos != str.npos) && ((str[nextPos] == ' ') || (str[nextPos] == '\t'))) + template static auto deduce(T &range) { - // Insert the quote now since we'll need to otherwise stomp over data we're about to write - // NOTE: By updating the search string here, we don't need to worry about manually inserting the - // character later since we'll just include it in our next iteration - WI_ASSERT(!forceQuotes); // Otherwise, shouldn't be part of our search string - searchString = search_string_no_space; // We're already adding a quote; don't do it again - result.insert(startPos, 1, '"'); - terminateWithQuotes = true; + using std::begin; + return (*begin(range))[0]; } - result.append(str, pos, nextPos - pos); - pos = nextPos; - if (pos == str.npos) - break; + using type = decltype(deduce(wistd::declval())); + }; - if (str[pos] == '"') + template + using deduce_char_type_from_string_range_t = typename deduce_char_type_from_string_range::type; + + // Internal helper span-like type for passing arrays as an iterable collection + template struct iterable_span + { + T *pointer; + size_t size; + + constexpr T *begin() const noexcept { - // Kinda easy case; just escape the quotes, *unless* this is the first argument and we assume a path - if ((currentIndex > 0) || WI_IsFlagSet(flags, ArgvToCommandLineFlags::FirstArgumentIsNotPath)) + return pointer; + } + + constexpr T *end() const noexcept + { + return pointer + size; + } + }; + } // namespace details + /// @endcond + + //! Flags that control the behavior of `ArgvToCommandLine` + enum class ArgvToCommandLineFlags : uint8_t + { + None = 0, + + //! By default, arguments are only surrounded by quotes when necessary (i.e. the argument contains a space). + //! When this flag is specified, all arguments are surrounded with quotes, regardless of whether or not they + //! contain space(s). This is an optimization as it means that we are not required to search for spaces in each + //! argument and we don't need to potentially go back and insert a quotation character in the middle of the + //! string after we've already written part of the argument to the result. That said, wrapping all arguments + //! with quotes can have some adverse effects with some applications, most notably cmd.exe, which do their own + //! command line processing. + ForceQuotes = 0x01 << 0, + + //! `CommandLineToArgvW` has an "optimization" that assumes that the first argument is the path to an + //! executable. Because valid NTFS paths cannot contain quotation characters, `CommandLineToArgvW` disables its + //! quote escaping logic for the first argument. By default, `ArgvToCommandLine` aims to ensure that an argv + //! array can "round trip" to a string and back, meaning it tries to replicate this logic in reverse. This flag + //! disables this logic and escapes backslashes and quotes the same for all arguments, including the first one. + //! This is useful if the output string is only an intermediate command line string (e.g. if the executable path + //! is prepended later). + FirstArgumentIsNotPath = 0x01 << 1, + }; + DEFINE_ENUM_FLAG_OPERATORS(ArgvToCommandLineFlags); + + //! Performs the reverse operation of CommandLineToArgvW. + //! Converts an argv array to a command line string that is guaranteed to "round trip" with CommandLineToArgvW. That + //! is, a call to wil::ArgvToCommandLine followed by a call to ArgvToCommandLineW will produce the same array that + //! was passed to wil::ArgvToCommandLine. Note that the reverse is not true. I.e. calling ArgvToCommandLineW + //! followed by wil::ArgvToCommandLine will not produce the original string due to the optionality of of quotes in + //! the command line string. This functionality is useful in a number of scenarios, most notably: + //! 1. When implementing a "driver" application. That is, an application that consumes some command line + //! arguments, + //! translates others into new arguments, and preserves the rest, "forwarding" the resulting command line to + //! a separate application. + //! 2. When reading command line arguments from some data storage, e.g. from a JSON array, which then need to + //! get + //! compiled into a command line string that's used for creating a new process. + //! Unlike CommandLineToArgvW, this function accepts both "narrow" and "wide" strings to support calling both + //! CreateProcessW and CreateProcessA with the result. See the values in @ref wil::ArgvToCommandLineFlags for more + //! information on how to control the behavior of this function as well as scenarios when you may want to use each + //! one. + template > + inline std::basic_string ArgvToCommandLine(RangeT &&range, + ArgvToCommandLineFlags flags = ArgvToCommandLineFlags::None) + { + using string_type = std::basic_string; + using string_view_type = std::basic_string_view; + + // Somewhat of a hack to avoid the fact that we can't conditionalize a string literal on a template + static constexpr const CharT empty_string[] = {'\0'}; + static constexpr const CharT single_quote_string[] = {'"', '\0'}; + static constexpr const CharT space_string[] = {' ', '\0'}; + static constexpr const CharT quoted_space_string[] = {'"', ' ', '"', '\0'}; + + static constexpr const CharT search_string_no_space[] = {'\\', '"', '\0'}; + static constexpr const CharT search_string_with_space[] = {'\\', '"', ' ', '\t', '\0'}; + + const bool forceQuotes = WI_IsFlagSet(flags, ArgvToCommandLineFlags::ForceQuotes); + const CharT *const initialSearchString = forceQuotes ? search_string_no_space : search_string_with_space; + const CharT *prefix = forceQuotes ? single_quote_string : empty_string; + const CharT *const nextPrefix = forceQuotes ? quoted_space_string : space_string; + + string_type result; + int index = 0; + for (auto &&strRaw : range) + { + auto currentIndex = index++; + result += prefix; + + const CharT *searchString = initialSearchString; + + // Info just in case we need to come back and insert quotes + auto startPos = result.size(); + bool terminateWithQuotes = false; // With forceQuotes == true, this is baked into the prefix + + // We need to escape any quotes and CONDITIONALLY any backslashes + string_view_type str(strRaw); + size_t pos = 0; + while (pos < str.size()) + { + auto nextPos = str.find_first_of(searchString, pos); + if ((nextPos != str.npos) && ((str[nextPos] == ' ') || (str[nextPos] == '\t'))) { - result.append({'\\', '"'}); // Escape case + // Insert the quote now since we'll need to otherwise stomp over data we're about to write + // NOTE: By updating the search string here, we don't need to worry about manually inserting the + // character later since we'll just include it in our next iteration + WI_ASSERT(!forceQuotes); // Otherwise, shouldn't be part of our search string + searchString = search_string_no_space; // We're already adding a quote; don't do it again + result.insert(startPos, 1, '"'); + terminateWithQuotes = true; + } + + result.append(str, pos, nextPos - pos); + pos = nextPos; + if (pos == str.npos) + break; + + if (str[pos] == '"') + { + // Kinda easy case; just escape the quotes, *unless* this is the first argument and we assume a path + if ((currentIndex > 0) || WI_IsFlagSet(flags, ArgvToCommandLineFlags::FirstArgumentIsNotPath)) + { + result.append({'\\', '"'}); // Escape case + } + else + { + // Realistically, this likely signals a bug since paths cannot contain quotes. That said, the + // behavior of CommandLineToArgvW is to just preserve "interior" quotes, so we do that. + // NOTE: 'CommandLineToArgvW' treats "interior" quotes as terminating quotes when the executable + // path begins with a quote, even if the next character is not a space. This assert won't catch + // all of such issues as we may detect a space, and therefore the need to surroud the argument + // with quotes, later in the string; this is best effort. Such arguments wouldn't be valid and + // are not representable anyway + WI_ASSERT((pos > 0) && !WI_IsFlagSet(flags, ArgvToCommandLineFlags::ForceQuotes) && + !terminateWithQuotes); + result.push_back('"'); // Not escaping case + } + ++pos; // Skip past quote on next search + } + else if (str[pos] == '\\') + { + // More complex case... Only need to escape if followed by 0+ backslashes and then either a quote or + // the end of the string and we're adding quotes + nextPos = str.find_first_not_of(L'\\', pos); + + // NOTE: This is an optimization taking advantage of the fact that doing a double append of 1+ + // backslashes will be functionally equivalent to escaping each one. This copies all of the + // backslashes once. We _might_ do it again later + result.append(str, pos, nextPos - pos); + + // If this is the first argument and is being interpreted as a path, we never escape slashes + if ((currentIndex == 0) && !WI_IsFlagSet(flags, ArgvToCommandLineFlags::FirstArgumentIsNotPath)) + { + pos = nextPos; + continue; + } + + if ((nextPos != str.npos) && (str[nextPos] != L'"')) + { + // Simplest case... don't need to escape when followed by a non-quote character + pos = nextPos; + continue; + } + + // If this is the end of the string and we're not appending a quotation to the end, we're in the + // same boat as the above where we don't need to escape + if ((nextPos == str.npos) && !forceQuotes && !terminateWithQuotes) + { + pos = nextPos; + continue; + } + + // Otherwise, we need to escape all backslashes. See above; this can be done with another append + result.append(str, pos, nextPos - pos); + pos = nextPos; + if (pos != str.npos) + { + // Must be followed by a quote; make sure we escape it, too. NOTE: We should have already early + // exited if this argument is being interpreted as an executable path + WI_ASSERT(str[pos] == '"'); + result.append({'\\', '"'}); + ++pos; + } } else { - // Realistically, this likely signals a bug since paths cannot contain quotes. That said, the - // behavior of CommandLineToArgvW is to just preserve "interior" quotes, so we do that. - // NOTE: 'CommandLineToArgvW' treats "interior" quotes as terminating quotes when the executable - // path begins with a quote, even if the next character is not a space. This assert won't catch all - // of such issues as we may detect a space, and therefore the need to surroud the argument with - // quotes, later in the string; this is best effort. Such arguments wouldn't be valid and are not - // representable anyway - WI_ASSERT((pos > 0) && !WI_IsFlagSet(flags, ArgvToCommandLineFlags::ForceQuotes) && !terminateWithQuotes); - result.push_back('"'); // Not escaping case + // Otherwise space, which we handled above + WI_ASSERT((str[pos] == ' ') || (str[pos] == '\t')); } - ++pos; // Skip past quote on next search } - else if (str[pos] == '\\') + + if (terminateWithQuotes) { - // More complex case... Only need to escape if followed by 0+ backslashes and then either a quote or - // the end of the string and we're adding quotes - nextPos = str.find_first_not_of(L'\\', pos); - - // NOTE: This is an optimization taking advantage of the fact that doing a double append of 1+ - // backslashes will be functionally equivalent to escaping each one. This copies all of the backslashes - // once. We _might_ do it again later - result.append(str, pos, nextPos - pos); - - // If this is the first argument and is being interpreted as a path, we never escape slashes - if ((currentIndex == 0) && !WI_IsFlagSet(flags, ArgvToCommandLineFlags::FirstArgumentIsNotPath)) - { - pos = nextPos; - continue; - } - - if ((nextPos != str.npos) && (str[nextPos] != L'"')) - { - // Simplest case... don't need to escape when followed by a non-quote character - pos = nextPos; - continue; - } - - // If this is the end of the string and we're not appending a quotation to the end, we're in the - // same boat as the above where we don't need to escape - if ((nextPos == str.npos) && !forceQuotes && !terminateWithQuotes) - { - pos = nextPos; - continue; - } - - // Otherwise, we need to escape all backslashes. See above; this can be done with another append - result.append(str, pos, nextPos - pos); - pos = nextPos; - if (pos != str.npos) - { - // Must be followed by a quote; make sure we escape it, too. NOTE: We should have already early - // exited if this argument is being interpreted as an executable path - WI_ASSERT(str[pos] == '"'); - result.append({'\\', '"'}); - ++pos; - } - } - else - { - // Otherwise space, which we handled above - WI_ASSERT((str[pos] == ' ') || (str[pos] == '\t')); + result.push_back('"'); } + + prefix = nextPrefix; } - if (terminateWithQuotes) + // NOTE: We optimize the force quotes case by including them in the prefix string. We're not appending a prefix + // anymore, so we need to make sure we close off the string + if (forceQuotes) { - result.push_back('"'); + result.push_back(L'\"'); } - prefix = nextPrefix; + return result; } - // NOTE: We optimize the force quotes case by including them in the prefix string. We're not appending a prefix - // anymore, so we need to make sure we close off the string - if (forceQuotes) + template + inline std::basic_string> ArgvToCommandLine( + int argc, CharT *const *argv, ArgvToCommandLineFlags flags = ArgvToCommandLineFlags::None) { - result.push_back(L'\"'); + return ArgvToCommandLine(details::iterable_span{argv, static_cast(argc)}, flags); } - - return result; -} - -template -inline std::basic_string> ArgvToCommandLine( - int argc, CharT* const* argv, ArgvToCommandLineFlags flags = ArgvToCommandLineFlags::None) -{ - return ArgvToCommandLine(details::iterable_span{argv, static_cast(argc)}, flags); -} #endif } // namespace wil @@ -1137,6 +1156,6 @@ inline std::basic_string> ArgvToCommandLine( // sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0); // } // Declaration -#define GetProcAddressByFunctionDeclaration(hinst, fn) reinterpret_cast(GetProcAddress(hinst, #fn)) +#define GetProcAddressByFunctionDeclaration(hinst, fn) reinterpret_cast(GetProcAddress(hinst, #fn)) #endif // __WIL_WIN32_HELPERS_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_result_macros.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_result_macros.h index fd60989..a896d07 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_result_macros.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/win32_result_macros.h @@ -9,8 +9,8 @@ // //********************************************************* //! @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. +//! 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 @@ -18,16 +18,16 @@ // 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; \ - } \ +#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)) @@ -50,99 +50,100 @@ FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr) #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); \ - } \ - } \ +#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); \ - } \ - } \ +#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); \ - } \ - } \ +#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); \ - } \ - } \ +#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); \ - } \ - } \ +#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; \ - } \ - } \ +// 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); \ - } \ - } \ +#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); \ - } \ - } \ +#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()); \ - } \ - } \ +#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()); \ - } \ - } \ +#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) //***************************************************************************** @@ -153,53 +154,55 @@ FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr) #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(); \ +#define WIN32_CATCH_RETURN() \ + catch (...) \ + { \ + WIN32_RETURN_CAUGHT_EXCEPTION(); \ } namespace wil { -//***************************************************************************** -// Public Helpers that catch -- mostly only enabled when exceptions are enabled -//***************************************************************************** + //***************************************************************************** + // 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 + // 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 { - __R_FN_LOCALS; - return __WIN32_FROM_HRESULT(wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY)); + 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(__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(__R_DIRECT_FN_CALL_ONLY)); - } -} // namespace details::__R_NS_NAME -/// @endcond + __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(__R_DIRECT_FN_CALL_ONLY)); + } + } // namespace details::__R_NS_NAME + /// @endcond } // namespace wil #endif // __WIL_WIN32_RESULTMACROS_INCLUDED diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/windowing.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/windowing.h index d21cd2b..831d11a 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/windowing.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/windowing.h @@ -19,71 +19,23 @@ #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) namespace wil { -namespace details -{ - template - struct always_false : wistd::false_type + namespace details { - }; + template struct always_false : wistd::false_type + { + }; - template - BOOL __stdcall EnumWindowsCallbackNoThrow(HWND hwnd, LPARAM lParam) - { - auto pCallback = reinterpret_cast(lParam); -#if __cpp_if_constexpr >= 201606L - using result_t = decltype((*pCallback)(hwnd)); - if constexpr (wistd::is_void_v) + template BOOL __stdcall EnumWindowsCallbackNoThrow(HWND hwnd, LPARAM lParam) { - (*pCallback)(hwnd); - return TRUE; - } - else if constexpr (wistd::is_same_v) - { - // 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) - { - return (*pCallback)(hwnd) ? TRUE : FALSE; - } - else - { - static_assert(details::always_false::value, "Callback must return void, bool, or HRESULT"); - } -#else - return (*pCallback)(hwnd); -#endif - } - - template - void DoEnumWindowsNoThrow(TEnumApi&& enumApi, TCallback&& callback) noexcept - { - enumApi(EnumWindowsCallbackNoThrow, reinterpret_cast(&callback)); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template - struct EnumWindowsCallbackData - { - std::exception_ptr exception; - TCallback* pCallback; - }; - - template - BOOL __stdcall EnumWindowsCallback(HWND hwnd, LPARAM lParam) - { - auto pCallbackData = reinterpret_cast*>(lParam); - try - { - auto pCallback = pCallbackData->pCallback; + auto pCallback = reinterpret_cast(lParam); #if __cpp_if_constexpr >= 201606L using result_t = decltype((*pCallback)(hwnd)); - if constexpr (std::is_void_v) + if constexpr (wistd::is_void_v) { (*pCallback)(hwnd); return TRUE; } - else if constexpr (std::is_same_v) + else if constexpr (wistd::is_same_v) { // NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0 return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE; @@ -100,74 +52,114 @@ namespace details return (*pCallback)(hwnd); #endif } - catch (...) + + template + void DoEnumWindowsNoThrow(TEnumApi &&enumApi, TCallback &&callback) noexcept { - pCallbackData->exception = std::current_exception(); - return FALSE; + enumApi(EnumWindowsCallbackNoThrow, reinterpret_cast(&callback)); } - }; - - template - void DoEnumWindows(TEnumApi&& enumApi, TCallback&& callback) - { - EnumWindowsCallbackData callbackData = {nullptr, &callback}; - enumApi(EnumWindowsCallback, reinterpret_cast(&callbackData)); - if (callbackData.exception) - { - std::rethrow_exception(callbackData.exception); - } - } -#endif -} // namespace details - -template -void for_each_window_nothrow(TCallback&& callback) noexcept -{ - details::DoEnumWindowsNoThrow(&EnumWindows, wistd::forward(callback)); -} - -template -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(callback)); -} - -template -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(callback)); -} #ifdef WIL_ENABLE_EXCEPTIONS -template -void for_each_window(TCallback&& callback) -{ - details::DoEnumWindows(&EnumWindows, wistd::forward(callback)); -} + template struct EnumWindowsCallbackData + { + std::exception_ptr exception; + TCallback *pCallback; + }; -template -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(callback)); -} + template BOOL __stdcall EnumWindowsCallback(HWND hwnd, LPARAM lParam) + { + auto pCallbackData = reinterpret_cast *>(lParam); + try + { + auto pCallback = pCallbackData->pCallback; +#if __cpp_if_constexpr >= 201606L + using result_t = decltype((*pCallback)(hwnd)); + if constexpr (std::is_void_v) + { + (*pCallback)(hwnd); + return TRUE; + } + else if constexpr (std::is_same_v) + { + // 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) + { + return (*pCallback)(hwnd) ? TRUE : FALSE; + } + else + { + static_assert(details::always_false::value, + "Callback must return void, bool, or HRESULT"); + } +#else + return (*pCallback)(hwnd); +#endif + } + catch (...) + { + pCallbackData->exception = std::current_exception(); + return FALSE; + } + }; -template -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(callback)); -} + template void DoEnumWindows(TEnumApi &&enumApi, TCallback &&callback) + { + EnumWindowsCallbackData callbackData = {nullptr, &callback}; + enumApi(EnumWindowsCallback, reinterpret_cast(&callbackData)); + if (callbackData.exception) + { + std::rethrow_exception(callbackData.exception); + } + } +#endif + } // namespace details + + template void for_each_window_nothrow(TCallback &&callback) noexcept + { + details::DoEnumWindowsNoThrow(&EnumWindows, wistd::forward(callback)); + } + + template + 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(callback)); + } + + template + 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(callback)); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + template void for_each_window(TCallback &&callback) + { + details::DoEnumWindows(&EnumWindows, wistd::forward(callback)); + } + + template 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(callback)); + } + + template 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(callback)); + } #endif } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/winrt.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/winrt.h index 43a06d2..6d7b743 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/winrt.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/winrt.h @@ -13,16 +13,16 @@ #ifndef __WIL_WINRT_INCLUDED #define __WIL_WINRT_INCLUDED -#include -#include -#include -#include -#include -#include "result.h" #include "com.h" #include "resource.h" -#include +#include "result.h" +#include #include +#include +#include +#include +#include +#include #ifdef __cplusplus_winrt #include // bring in the CRT iterator for support for C++ CX code @@ -50,510 +50,514 @@ namespace wil { -// time_t is the number of 1 - second intervals since January 1, 1970. -constexpr long long SecondsToStartOf1970 = 0x2b6109100; -constexpr long long HundredNanoSecondsInSecond = 10000000LL; + // time_t is the number of 1 - second intervals since January 1, 1970. + constexpr long long SecondsToStartOf1970 = 0x2b6109100; + constexpr long long HundredNanoSecondsInSecond = 10000000LL; -inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime) -{ - // DateTime is the number of 100 - nanosecond intervals since January 1, 1601. - return (dateTime.UniversalTime / HundredNanoSecondsInSecond - SecondsToStartOf1970); -} + inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime) + { + // DateTime is the number of 100 - nanosecond intervals since January 1, 1601. + return (dateTime.UniversalTime / HundredNanoSecondsInSecond - SecondsToStartOf1970); + } -inline ABI::Windows::Foundation::DateTime time_t_to_DateTime(__time64_t timeT) -{ - ABI::Windows::Foundation::DateTime dateTime; - dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond; - return dateTime; -} + inline ABI::Windows::Foundation::DateTime time_t_to_DateTime(__time64_t timeT) + { + ABI::Windows::Foundation::DateTime dateTime; + dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond; + return dateTime; + } #pragma region HSTRING Helpers -/// @cond -namespace details -{ - // hstring_compare is used to assist in HSTRING comparison of two potentially non-similar string types. E.g. - // comparing a raw HSTRING with WRL's HString/HStringReference/etc. The consumer can optionally inhibit the - // deduction of array sizes by providing 'true' for the 'InhibitStringArrays' template argument. This is - // generally done in scenarios where the consumer cannot guarantee that the input argument types are perfectly - // preserved from end-to-end. E.g. if a single function in the execution path captures an array as const T&, - // then it is impossible to differentiate const arrays (where we generally do want to deduce length) from - // non-const arrays (where we generally do not want to deduce length). The consumer can also optionally choose - // to perform case-insensitive comparison by providing 'true' for the 'IgnoreCase' template argument. - template - struct hstring_compare + /// @cond + namespace details { - // get_buffer returns the string buffer and length for the supported string types - static const wchar_t* get_buffer(HSTRING hstr, UINT32* length) WI_NOEXCEPT + // hstring_compare is used to assist in HSTRING comparison of two potentially non-similar string types. E.g. + // comparing a raw HSTRING with WRL's HString/HStringReference/etc. The consumer can optionally inhibit the + // deduction of array sizes by providing 'true' for the 'InhibitStringArrays' template argument. This is + // generally done in scenarios where the consumer cannot guarantee that the input argument types are perfectly + // preserved from end-to-end. E.g. if a single function in the execution path captures an array as const T&, + // then it is impossible to differentiate const arrays (where we generally do want to deduce length) from + // non-const arrays (where we generally do not want to deduce length). The consumer can also optionally choose + // to perform case-insensitive comparison by providing 'true' for the 'IgnoreCase' template argument. + template struct hstring_compare { - return ::WindowsGetStringRawBuffer(hstr, length); + // get_buffer returns the string buffer and length for the supported string types + static const wchar_t *get_buffer(HSTRING hstr, UINT32 *length) WI_NOEXCEPT + { + return ::WindowsGetStringRawBuffer(hstr, length); + } + + static const wchar_t *get_buffer(const Microsoft::WRL::Wrappers::HString &hstr, UINT32 *length) WI_NOEXCEPT + { + return hstr.GetRawBuffer(length); + } + + static const wchar_t *get_buffer(const Microsoft::WRL::Wrappers::HStringReference &hstr, + UINT32 *length) WI_NOEXCEPT + { + return hstr.GetRawBuffer(length); + } + + static const wchar_t *get_buffer(const unique_hstring &str, UINT32 *length) WI_NOEXCEPT + { + return ::WindowsGetStringRawBuffer(str.get(), length); + } + + template + static wistd::enable_if_t get_buffer(const wchar_t *str, + UINT32 *length) WI_NOEXCEPT + { + str = (str != nullptr) ? str : L""; + *length = static_cast(wcslen(str)); + return str; + } + + template + static wistd::enable_if_t< + wistd::conjunction, + wistd::is_same>, wchar_t>, + wistd::bool_constant>::value, + const wchar_t *> + get_buffer(StringT str, UINT32 *length) WI_NOEXCEPT + { + str = (str != nullptr) ? str : L""; + *length = static_cast(wcslen(str)); + return str; + } + + template + static wistd::enable_if_t get_buffer(const wchar_t (&str)[Size], + UINT32 *length) WI_NOEXCEPT + { + *length = Size - 1; + return str; + } + + template + static wistd::enable_if_t get_buffer(wchar_t (&str)[Size], + UINT32 *length) WI_NOEXCEPT + { + *length = static_cast(wcslen(str)); + return str; + } + + // Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency + // on STL headers + template + static wistd::enable_if_t< + wistd::conjunction_v< + wistd::is_constructible, + wistd::is_convertible().data()), const wchar_t *>, + wistd::is_same().size())>>, + const wchar_t *> + get_buffer(const StringT &str, UINT32 *length) WI_NOEXCEPT + { + *length = static_cast(str.size()); + const wchar_t *ret = str.data(); + return ret ? ret : L""; + } + + template + static auto compare(LhsT &&lhs, RhsT &&rhs) -> decltype(get_buffer(lhs, wistd::declval()), + get_buffer(rhs, wistd::declval()), int()) + { + UINT32 lhsLength; + UINT32 rhsLength; + auto lhsBuffer = get_buffer(wistd::forward(lhs), &lhsLength); + auto rhsBuffer = get_buffer(wistd::forward(rhs), &rhsLength); + + const auto result = + ::CompareStringOrdinal(lhsBuffer, lhsLength, rhsBuffer, rhsLength, IgnoreCase ? TRUE : FALSE); + WI_ASSERT(result != 0); + + return result; + } + + template + static auto equals(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_EQUAL; + } + + template + static auto not_equals(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_EQUAL; + } + + template + static auto less(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_LESS_THAN; + } + + template + static auto less_equals(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_GREATER_THAN; + } + + template + static auto greater(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_GREATER_THAN; + } + + template + static auto greater_equals(LhsT &&lhs, RhsT &&rhs) WI_NOEXCEPT + -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_LESS_THAN; + } + }; + } // namespace details + /// @endcond + + //! Detects if one or more embedded null is present in an HSTRING. + inline bool HasEmbeddedNull(_In_opt_ HSTRING value) + { + BOOL hasEmbeddedNull = FALSE; + (void)WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull); + return hasEmbeddedNull != FALSE; + } + + /** TwoPhaseHStringConstructor help using the 2 phase constructor pattern for HSTRINGs. + @code + auto stringConstructor = wil::TwoPhaseHStringConstructor::Preallocate(size); + RETURN_IF_NULL_ALLOC(stringConstructor.Get()); + + RETURN_IF_FAILED(stream->Read(stringConstructor.Get(), stringConstructor.ByteSize(), &bytesRead)); + + // Validate stream contents, sizes must match, string must be null terminated. + RETURN_IF_FAILED(stringConstructor.Validate(bytesRead)); + + wil::unique_hstring string { stringConstructor.Promote() }; + @endcode + + See also wil::unique_hstring_buffer. + */ + struct TwoPhaseHStringConstructor + { + TwoPhaseHStringConstructor() = delete; + TwoPhaseHStringConstructor(const TwoPhaseHStringConstructor &) = delete; + void operator=(const TwoPhaseHStringConstructor &) = delete; + + TwoPhaseHStringConstructor(TwoPhaseHStringConstructor &&other) WI_NOEXCEPT + { + m_characterLength = other.m_characterLength; + other.m_characterLength = 0; + m_maker = wistd::move(other.m_maker); } - static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HString& hstr, UINT32* length) WI_NOEXCEPT + static TwoPhaseHStringConstructor Preallocate(UINT32 characterLength) { - return hstr.GetRawBuffer(length); + return TwoPhaseHStringConstructor{characterLength}; } - static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HStringReference& hstr, UINT32* length) WI_NOEXCEPT + //! Returns the HSTRING after it has been populated like Detach() or release(); be sure to put this in a RAII + //! type to manage its lifetime. + HSTRING Promote() { - return hstr.GetRawBuffer(length); + m_characterLength = 0; + return m_maker.release().release(); } - static const wchar_t* get_buffer(const unique_hstring& str, UINT32* length) WI_NOEXCEPT + ~TwoPhaseHStringConstructor() = default; + + WI_NODISCARD explicit operator PCWSTR() const { - return ::WindowsGetStringRawBuffer(str.get(), length); + // This is set by WindowsPromoteStringBuffer() which must be called to + // construct this object via the static method Preallocate(). + return m_maker.buffer(); } - template - static wistd::enable_if_t get_buffer(const wchar_t* str, UINT32* length) WI_NOEXCEPT + //! Returns a pointer for the buffer so it can be populated + WI_NODISCARD wchar_t *Get() const { - str = (str != nullptr) ? str : L""; - *length = static_cast(wcslen(str)); - return str; + return const_cast(m_maker.buffer()); + } + //! Used to validate range of buffer when populating. + WI_NODISCARD ULONG ByteSize() const + { + return m_characterLength * sizeof(wchar_t); } - template - static wistd::enable_if_t< - wistd::conjunction, wistd::is_same>, wchar_t>, wistd::bool_constant>::value, - const wchar_t*> - get_buffer(StringT str, UINT32* length) WI_NOEXCEPT + /** Ensure that the size of the data provided is consistent with the pre-allocated buffer. + It seems that WindowsPreallocateStringBuffer() provides the null terminator in the buffer + (based on testing) so this can be called before populating the buffer. + */ + WI_NODISCARD HRESULT Validate(ULONG bytesRead) const { - str = (str != nullptr) ? str : L""; - *length = static_cast(wcslen(str)); - return str; + // Null termination is required for the buffer before calling WindowsPromoteStringBuffer(). + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), + (bytesRead != ByteSize()) || (Get()[m_characterLength] != L'\0')); + return S_OK; } - template - static wistd::enable_if_t get_buffer(const wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT + private: + TwoPhaseHStringConstructor(UINT32 characterLength) : m_characterLength(characterLength) { - *length = Size - 1; - return str; + (void)m_maker.make(nullptr, characterLength); } - template - static wistd::enable_if_t get_buffer(wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT - { - *length = static_cast(wcslen(str)); - return str; - } + UINT32 m_characterLength; + details::string_maker m_maker; + }; - // Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency - // on STL headers - template - static wistd::enable_if_t< - wistd::conjunction_v< - wistd::is_constructible, - wistd::is_convertible().data()), const wchar_t*>, - wistd::is_same().size())>>, - const wchar_t*> - get_buffer(const StringT& str, UINT32* length) WI_NOEXCEPT - { - *length = static_cast(str.size()); - const wchar_t* ret = str.data(); - return ret ? ret : L""; - } + //! A transparent less-than comparison function object that enables comparison of various string types intended for + //! use with associative containers (such as `std::set`, `std::map`, etc.) that use + //! `Microsoft::WRL::Wrappers::HString` as the key type. This removes the need for the consumer to explicitly + //! create an `HString` object when using lookup functions such as `find`, `lower_bound`, etc. For example, the + //! following scenarios would all work exactly as you would expect them to: + //! ~~~ + //! std::map map; + //! const wchar_t constArray[] = L"foo"; + //! wchar_t nonConstArray[MAX_PATH] = L"foo"; + //! + //! HString key; + //! THROW_IF_FAILED(key.Set(constArray)); + //! map.emplace(std::move(key), 42); + //! + //! HString str; + //! wil::unique_hstring uniqueStr; + //! THROW_IF_FAILED(str.Set(L"foo")); + //! THROW_IF_FAILED(str.CopyTo(&uniqueStr)); + //! + //! // All of the following return an iterator to the pair { L"foo", 42 } + //! map.find(str); + //! map.find(str.Get()); + //! map.find(HStringReference(constArray)); + //! map.find(uniqueStr); + //! map.find(std::wstring(constArray)); + //! map.find(constArray); + //! map.find(nonConstArray); + //! map.find(static_cast(constArray)); + //! ~~~ + //! The first four calls in the example above use `WindowsGetStringRawBuffer` (or equivalent) to get the string + //! buffer and length for the comparison. The fifth example uses `std::wstring::c_str` and `std::wstring::length` + //! for getting these two values. The remaining three examples use only the string buffer and call `wcslen` for the + //! length. That is, the length is *not* deduced for either array. This is because argument types are not always + //! perfectly preserved by container functions and in fact are often captured as const references making it + //! impossible to differentiate const arrays - where we can safely deduce length - from non const arrays - where we + //! cannot safely deduce length since the buffer may be larger than actually needed (e.g. creating a + //! `char[MAX_PATH]` array, but only filling it with 10 characters). The implications of this behavior is that + //! string literals that contain embedded null characters will only include the part of the buffer up to the first + //! null character. For example, the following example will result in all calls to `find` returning an end + //! iterator. + //! ~~~ + //! std::map map; + //! const wchar_t constArray[] = L"foo\0bar"; + //! wchar_t nonConstArray[MAX_PATH] = L"foo\0bar"; + //! + //! // Create the key with the embedded null character + //! HString key; + //! THROW_IF_FAILED(key.Set(constArray)); + //! map.emplace(std::move(key), 42); + //! + //! // All of the following return map.end() since they look for the string "foo" + //! map.find(constArray); + //! map.find(nonConstArray); + //! map.find(static_cast(constArray)); + //! ~~~ + //! In order to search using a string literal that contains embedded null characters, a simple alternative is to + //! first create an `HStringReference` and use that for the function call: + //! ~~~ + //! // HStringReference's constructor *will* deduce the length of const arrays + //! map.find(HStringReference(constArray)); + //! ~~~ + struct hstring_less + { + using is_transparent = void; template - static auto compare(LhsT&& lhs, RhsT&& rhs) - -> decltype(get_buffer(lhs, wistd::declval()), get_buffer(rhs, wistd::declval()), int()) + WI_NODISCARD auto operator()(const LhsT &lhs, const RhsT &rhs) const + WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) { - UINT32 lhsLength; - UINT32 rhsLength; - auto lhsBuffer = get_buffer(wistd::forward(lhs), &lhsLength); - auto rhsBuffer = get_buffer(wistd::forward(rhs), &rhsLength); - - const auto result = ::CompareStringOrdinal(lhsBuffer, lhsLength, rhsBuffer, rhsLength, IgnoreCase ? TRUE : FALSE); - WI_ASSERT(result != 0); - - return result; - } - - template - static auto equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_EQUAL; - } - - template - static auto not_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_EQUAL; - } - - template - static auto less(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_LESS_THAN; - } - - template - static auto less_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_GREATER_THAN; - } - - template - static auto greater(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_GREATER_THAN; - } - - template - static auto greater_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT - -> decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_LESS_THAN; + return details::hstring_compare::less(lhs, rhs); } }; -} // namespace details -/// @endcond -//! Detects if one or more embedded null is present in an HSTRING. -inline bool HasEmbeddedNull(_In_opt_ HSTRING value) -{ - BOOL hasEmbeddedNull = FALSE; - (void)WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull); - return hasEmbeddedNull != FALSE; -} - -/** TwoPhaseHStringConstructor help using the 2 phase constructor pattern for HSTRINGs. -@code -auto stringConstructor = wil::TwoPhaseHStringConstructor::Preallocate(size); -RETURN_IF_NULL_ALLOC(stringConstructor.Get()); - -RETURN_IF_FAILED(stream->Read(stringConstructor.Get(), stringConstructor.ByteSize(), &bytesRead)); - -// Validate stream contents, sizes must match, string must be null terminated. -RETURN_IF_FAILED(stringConstructor.Validate(bytesRead)); - -wil::unique_hstring string { stringConstructor.Promote() }; -@endcode - -See also wil::unique_hstring_buffer. -*/ -struct TwoPhaseHStringConstructor -{ - TwoPhaseHStringConstructor() = delete; - TwoPhaseHStringConstructor(const TwoPhaseHStringConstructor&) = delete; - void operator=(const TwoPhaseHStringConstructor&) = delete; - - TwoPhaseHStringConstructor(TwoPhaseHStringConstructor&& other) WI_NOEXCEPT + //! A transparent less-than comparison function object whose behavior is equivalent to that of @ref hstring_less + //! with the one difference that comparisons are case-insensitive. That is, the following example will correctly + //! find the inserted value: + //! ~~~ + //! std::map map; + //! + //! HString key; + //! THROW_IF_FAILED(key.Set(L"foo")); + //! map.emplace(std::move(key), 42); + //! + //! // All of the following return an iterator to the pair { L"foo", 42 } + //! map.find(L"FOo"); + //! map.find(HStringReference(L"fOo")); + //! map.find(HStringReference(L"fOO").Get()); + //! ~~~ + struct hstring_insensitive_less { - m_characterLength = other.m_characterLength; - other.m_characterLength = 0; - m_maker = wistd::move(other.m_maker); - } + using is_transparent = void; - static TwoPhaseHStringConstructor Preallocate(UINT32 characterLength) - { - return TwoPhaseHStringConstructor{characterLength}; - } - - //! Returns the HSTRING after it has been populated like Detach() or release(); be sure to put this in a RAII type to manage - //! its lifetime. - HSTRING Promote() - { - m_characterLength = 0; - return m_maker.release().release(); - } - - ~TwoPhaseHStringConstructor() = default; - - WI_NODISCARD explicit operator PCWSTR() const - { - // This is set by WindowsPromoteStringBuffer() which must be called to - // construct this object via the static method Preallocate(). - return m_maker.buffer(); - } - - //! Returns a pointer for the buffer so it can be populated - WI_NODISCARD wchar_t* Get() const - { - return const_cast(m_maker.buffer()); - } - //! Used to validate range of buffer when populating. - WI_NODISCARD ULONG ByteSize() const - { - return m_characterLength * sizeof(wchar_t); - } - - /** Ensure that the size of the data provided is consistent with the pre-allocated buffer. - It seems that WindowsPreallocateStringBuffer() provides the null terminator in the buffer - (based on testing) so this can be called before populating the buffer. - */ - WI_NODISCARD HRESULT Validate(ULONG bytesRead) const - { - // Null termination is required for the buffer before calling WindowsPromoteStringBuffer(). - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), (bytesRead != ByteSize()) || (Get()[m_characterLength] != L'\0')); - return S_OK; - } - -private: - TwoPhaseHStringConstructor(UINT32 characterLength) : m_characterLength(characterLength) - { - (void)m_maker.make(nullptr, characterLength); - } - - UINT32 m_characterLength; - details::string_maker m_maker; -}; - -//! A transparent less-than comparison function object that enables comparison of various string types intended for -//! use with associative containers (such as `std::set`, `std::map`, etc.) that use -//! `Microsoft::WRL::Wrappers::HString` as the key type. This removes the need for the consumer to explicitly -//! create an `HString` object when using lookup functions such as `find`, `lower_bound`, etc. For example, the -//! following scenarios would all work exactly as you would expect them to: -//! ~~~ -//! std::map map; -//! const wchar_t constArray[] = L"foo"; -//! wchar_t nonConstArray[MAX_PATH] = L"foo"; -//! -//! HString key; -//! THROW_IF_FAILED(key.Set(constArray)); -//! map.emplace(std::move(key), 42); -//! -//! HString str; -//! wil::unique_hstring uniqueStr; -//! THROW_IF_FAILED(str.Set(L"foo")); -//! THROW_IF_FAILED(str.CopyTo(&uniqueStr)); -//! -//! // All of the following return an iterator to the pair { L"foo", 42 } -//! map.find(str); -//! map.find(str.Get()); -//! map.find(HStringReference(constArray)); -//! map.find(uniqueStr); -//! map.find(std::wstring(constArray)); -//! map.find(constArray); -//! map.find(nonConstArray); -//! map.find(static_cast(constArray)); -//! ~~~ -//! The first four calls in the example above use `WindowsGetStringRawBuffer` (or equivalent) to get the string -//! buffer and length for the comparison. The fifth example uses `std::wstring::c_str` and `std::wstring::length` -//! for getting these two values. The remaining three examples use only the string buffer and call `wcslen` for the -//! length. That is, the length is *not* deduced for either array. This is because argument types are not always -//! perfectly preserved by container functions and in fact are often captured as const references making it -//! impossible to differentiate const arrays - where we can safely deduce length - from non const arrays - where we -//! cannot safely deduce length since the buffer may be larger than actually needed (e.g. creating a -//! `char[MAX_PATH]` array, but only filling it with 10 characters). The implications of this behavior is that -//! string literals that contain embedded null characters will only include the part of the buffer up to the first -//! null character. For example, the following example will result in all calls to `find` returning an end -//! iterator. -//! ~~~ -//! std::map map; -//! const wchar_t constArray[] = L"foo\0bar"; -//! wchar_t nonConstArray[MAX_PATH] = L"foo\0bar"; -//! -//! // Create the key with the embedded null character -//! HString key; -//! THROW_IF_FAILED(key.Set(constArray)); -//! map.emplace(std::move(key), 42); -//! -//! // All of the following return map.end() since they look for the string "foo" -//! map.find(constArray); -//! map.find(nonConstArray); -//! map.find(static_cast(constArray)); -//! ~~~ -//! In order to search using a string literal that contains embedded null characters, a simple alternative is to -//! first create an `HStringReference` and use that for the function call: -//! ~~~ -//! // HStringReference's constructor *will* deduce the length of const arrays -//! map.find(HStringReference(constArray)); -//! ~~~ -struct hstring_less -{ - using is_transparent = void; - - template - WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const - WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) - { - return details::hstring_compare::less(lhs, rhs); - } -}; - -//! A transparent less-than comparison function object whose behavior is equivalent to that of @ref hstring_less -//! with the one difference that comparisons are case-insensitive. That is, the following example will correctly -//! find the inserted value: -//! ~~~ -//! std::map map; -//! -//! HString key; -//! THROW_IF_FAILED(key.Set(L"foo")); -//! map.emplace(std::move(key), 42); -//! -//! // All of the following return an iterator to the pair { L"foo", 42 } -//! map.find(L"FOo"); -//! map.find(HStringReference(L"fOo")); -//! map.find(HStringReference(L"fOO").Get()); -//! ~~~ -struct hstring_insensitive_less -{ - using is_transparent = void; - - template - WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const - WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) - { - return details::hstring_compare::less(lhs, rhs); - } -}; + template + WI_NODISCARD auto operator()(const LhsT &lhs, const RhsT &rhs) const + WI_NOEXCEPT->decltype(details::hstring_compare::less(lhs, rhs)) + { + return details::hstring_compare::less(lhs, rhs); + } + }; #pragma endregion -/// @cond -namespace details -{ - // MapToSmartType::type is used to map a raw type into an RAII expression - // of it. This is needed when lifetime management of the type is needed, for example - // when holding them as a value produced in an iterator. - // This type has a common set of methods used to abstract the access to the value - // that is similar to ComPtr<> and the WRL Wrappers: Get(), GetAddressOf() and other operators. - // Clients of the smart type must use those to access the value. - - // TODO: Having the base definition defined will result in creating leaks if a type - // that needs resource management (e.g. PROPVARIANT) that has not specialized is used. - // - // One fix is to use std::is_enum to cover that case and leave the base definition undefined. - // That base should use static_assert to inform clients how to fix the lack of specialization. - template - struct MapToSmartType + /// @cond + namespace details { + // MapToSmartType::type is used to map a raw type into an RAII expression + // of it. This is needed when lifetime management of the type is needed, for example + // when holding them as a value produced in an iterator. + // This type has a common set of methods used to abstract the access to the value + // that is similar to ComPtr<> and the WRL Wrappers: Get(), GetAddressOf() and other operators. + // Clients of the smart type must use those to access the value. + + // TODO: Having the base definition defined will result in creating leaks if a type + // that needs resource management (e.g. PROPVARIANT) that has not specialized is used. + // + // One fix is to use std::is_enum to cover that case and leave the base definition undefined. + // That base should use static_assert to inform clients how to fix the lack of specialization. + template struct MapToSmartType + { #pragma warning(push) #pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2 - struct type // T holder - { - type() = default; - type(T&& value) : m_value(wistd::forward(value)) + struct type // T holder { - } - WI_NODISCARD operator T() const - { - return m_value; - } - type& operator=(T&& value) - { - m_value = wistd::forward(value); - return *this; - } - WI_NODISCARD T Get() const - { - return m_value; - } + type() = default; + type(T &&value) : m_value(wistd::forward(value)) + { + } + WI_NODISCARD operator T() const + { + return m_value; + } + type &operator=(T &&value) + { + m_value = wistd::forward(value); + return *this; + } + WI_NODISCARD T Get() const + { + return m_value; + } - // Returning T&& to support move only types - // In case of absence of T::operator=(T&&) a call to T::operator=(const T&) will happen - T&& Get() - { - return wistd::move(m_value); - } + // Returning T&& to support move only types + // In case of absence of T::operator=(T&&) a call to T::operator=(const T&) will happen + T &&Get() + { + return wistd::move(m_value); + } - WI_NODISCARD HRESULT CopyTo(T* result) const - { - *result = m_value; - return S_OK; - } - T* GetAddressOf() - { - return &m_value; - } - T* ReleaseAndGetAddressOf() - { - return &m_value; - } - T* operator&() - { - return &m_value; - } - T m_value{}; - }; + WI_NODISCARD HRESULT CopyTo(T *result) const + { + *result = m_value; + return S_OK; + } + T *GetAddressOf() + { + return &m_value; + } + T *ReleaseAndGetAddressOf() + { + return &m_value; + } + T *operator&() + { + return &m_value; + } + T m_value{}; + }; #pragma warning(pop) - }; - - // IUnknown * derived -> Microsoft::WRL::ComPtr<> - template - struct MapToSmartType::type>::value>::type> - { - typedef Microsoft::WRL::ComPtr::type> type; - }; - - // HSTRING -> Microsoft::WRL::Wrappers::HString - template <> - struct MapToSmartType - { - class HStringWithRelease : public Microsoft::WRL::Wrappers::HString - { - public: - // Unlike all other WRL types HString does not have ReleaseAndGetAddressOf and - // GetAddressOf() has non-standard behavior, calling Release(). - HSTRING* ReleaseAndGetAddressOf() WI_NOEXCEPT - { - Release(); - return &hstr_; - } }; - typedef HStringWithRelease type; - }; - // WinRT interfaces like IVector<>, IAsyncOperation<> and IIterable<> can be templated - // on a runtime class (instead of an interface or primitive type). In these cases the objects - // produced by those interfaces implement an interface defined by the runtime class default interface. - // - // These templates deduce the type of the produced interface or pass through - // the type unmodified in the non runtime class case. - // - // for example: - // IAsyncOperation -> IAsyncOperation + // IUnknown * derived -> Microsoft::WRL::ComPtr<> + template + struct MapToSmartType::type>::value>::type> + { + typedef Microsoft::WRL::ComPtr::type> type; + }; - // For IVector, IVectorView. - template - struct MapVectorResultType - { - template - static TResult PeekGetAtType(HRESULT (STDMETHODCALLTYPE TVector::*)(unsigned, TResult*)); - typedef decltype(PeekGetAtType(&VectorType::GetAt)) type; - }; + // HSTRING -> Microsoft::WRL::Wrappers::HString + template <> struct MapToSmartType + { + class HStringWithRelease : public Microsoft::WRL::Wrappers::HString + { + public: + // Unlike all other WRL types HString does not have ReleaseAndGetAddressOf and + // GetAddressOf() has non-standard behavior, calling Release(). + HSTRING *ReleaseAndGetAddressOf() WI_NOEXCEPT + { + Release(); + return &hstr_; + } + }; + typedef HStringWithRelease type; + }; - // For IIterator. - template - struct MapIteratorResultType - { - template - static TResult PeekCurrentType(HRESULT (STDMETHODCALLTYPE TIterable::*)(TResult*)); - typedef decltype(PeekCurrentType(&ABI::Windows::Foundation::Collections::IIterator::get_Current)) type; - }; + // WinRT interfaces like IVector<>, IAsyncOperation<> and IIterable<> can be templated + // on a runtime class (instead of an interface or primitive type). In these cases the objects + // produced by those interfaces implement an interface defined by the runtime class default interface. + // + // These templates deduce the type of the produced interface or pass through + // the type unmodified in the non runtime class case. + // + // for example: + // IAsyncOperation -> IAsyncOperation - // For IAsyncOperation. - template - struct MapAsyncOpResultType - { - template - static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); - typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperation::GetResults)) type; - }; + // For IVector, IVectorView. + template struct MapVectorResultType + { + template + static TResult PeekGetAtType(HRESULT (STDMETHODCALLTYPE TVector::*)(unsigned, TResult *)); + typedef decltype(PeekGetAtType(&VectorType::GetAt)) type; + }; - // For IAsyncOperationWithProgress. - template - struct MapAsyncOpProgressResultType - { - template - static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); - typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperationWithProgress::GetResults)) type; - }; + // For IIterator. + template struct MapIteratorResultType + { + template + static TResult PeekCurrentType(HRESULT (STDMETHODCALLTYPE TIterable::*)(TResult *)); + typedef decltype(PeekCurrentType(&ABI::Windows::Foundation::Collections::IIterator::get_Current)) type; + }; - // No support for IAsyncActionWithProgress

none of these (currently) use - // a runtime class for the progress type. -} // namespace details + // For IAsyncOperation. + template struct MapAsyncOpResultType + { + template + static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult *)); + typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperation::GetResults)) type; + }; + + // For IAsyncOperationWithProgress. + template struct MapAsyncOpProgressResultType + { + template + static TResult PeekGetResultsType(HRESULT (STDMETHODCALLTYPE TAsyncOperation::*)(TResult *)); + typedef decltype(PeekGetResultsType( + &ABI::Windows::Foundation::IAsyncOperationWithProgress::GetResults)) type; + }; + + // No support for IAsyncActionWithProgress

none of these (currently) use + // a runtime class for the progress type. + } // namespace details /// @endcond #pragma region C++ iterators for WinRT collections for use with range based for and STL algorithms /** Range base for and STL algorithms support for WinRT ABI collection types, IVector, IVectorView, IIterable similar to support provided by for C++ CX. Three error handling policies are supported. @code -ComPtr collection = GetCollection(); // can be IVector, IVectorView or IIterable +ComPtr collection = GetCollection(); // can be IVector, IVectorView or +IIterable for (auto const& element : wil::get_range(collection.Get())) // exceptions for (auto const& element : wil::get_range_nothrow(collection.Get(), &hr)) // error code @@ -574,639 +578,456 @@ auto itFound = std::find_if(fileRange.begin(), fileRange.end(), [](ComPtr/IVectorView<> -template -class vector_range -{ -public: - typedef typename details::MapVectorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - vector_range() = delete; - - explicit vector_range(_In_ VectorType* vector) : m_v(vector) + template class vector_range { - } + public: + typedef typename details::MapVectorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; - class vector_iterator - { - public: + vector_range() = delete; + + explicit vector_range(_In_ VectorType *vector) : m_v(vector) + { + } + + class vector_iterator + { + public: #if WIL_USE_STL || defined(WIL_DOXYGEN) - // could be random_access_iterator_tag but missing some features - typedef ::std::bidirectional_iterator_tag iterator_category; + // could be random_access_iterator_tag but missing some features + typedef ::std::bidirectional_iterator_tag iterator_category; #endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart *pointer; + typedef const TSmart &reference; - // for begin() - vector_iterator(VectorType* v, unsigned int pos) : m_v(v), m_i(pos) - { - } + // for begin() + vector_iterator(VectorType *v, unsigned int pos) : m_v(v), m_i(pos) + { + } - // for end() - vector_iterator() : m_v(nullptr), m_i(-1) - { - } + // for end() + vector_iterator() : m_v(nullptr), m_i(-1) + { + } - vector_iterator(const vector_iterator& other) - { - m_v = other.m_v; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); - } - - vector_iterator& operator=(const vector_iterator& other) - { - if (this != wistd::addressof(other)) + vector_iterator(const vector_iterator &other) { m_v = other.m_v; m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); + err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); } - return *this; - } - reference operator*() + vector_iterator &operator=(const vector_iterator &other) + { + if (this != wistd::addressof(other)) + { + m_v = other.m_v; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); + } + return *this; + } + + reference operator*() + { + err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); + return m_element; + } + + pointer operator->() + { + err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); + return wistd::addressof(m_element); + } + + vector_iterator &operator++() + { + ++m_i; + return *this; + } + + vector_iterator &operator--() + { + --m_i; + return *this; + } + + vector_iterator operator++(int) + { + vector_iterator old(*this); + ++*this; + return old; + } + + vector_iterator operator--(int) + { + vector_iterator old(*this); + --*this; + return old; + } + + vector_iterator &operator+=(int n) + { + m_i += n; + return *this; + } + + vector_iterator &operator-=(int n) + { + m_i -= n; + return *this; + } + + WI_NODISCARD vector_iterator operator+(int n) const + { + vector_iterator ret(*this); + ret += n; + return ret; + } + + WI_NODISCARD vector_iterator operator-(int n) const + { + vector_iterator ret(*this); + ret -= n; + return ret; + } + + WI_NODISCARD ptrdiff_t operator-(const vector_iterator &other) const + { + return m_i - other.m_i; + } + + WI_NODISCARD bool operator==(const vector_iterator &other) const + { + return m_i == other.m_i; + } + + WI_NODISCARD bool operator!=(const vector_iterator &other) const + { + return m_i != other.m_i; + } + + WI_NODISCARD bool operator<(const vector_iterator &other) const + { + return m_i < other.m_i; + } + + WI_NODISCARD bool operator>(const vector_iterator &other) const + { + return m_i > other.m_i; + } + + WI_NODISCARD bool operator<=(const vector_iterator &other) const + { + return m_i <= other.m_i; + } + + WI_NODISCARD bool operator>=(const vector_iterator &other) const + { + return m_i >= other.m_i; + } + + private: + VectorType *m_v; // weak, collection must outlive iterators. + unsigned int m_i; + TSmart m_element; + }; + + vector_iterator begin() { - err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); - return m_element; + return vector_iterator(m_v, 0); } - pointer operator->() + vector_iterator end() { - err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); - return wistd::addressof(m_element); + unsigned int size; + err_policy::HResult(m_v->get_Size(&size)); + return vector_iterator(m_v, size); } - vector_iterator& operator++() - { - ++m_i; - return *this; - } - - vector_iterator& operator--() - { - --m_i; - return *this; - } - - vector_iterator operator++(int) - { - vector_iterator old(*this); - ++*this; - return old; - } - - vector_iterator operator--(int) - { - vector_iterator old(*this); - --*this; - return old; - } - - vector_iterator& operator+=(int n) - { - m_i += n; - return *this; - } - - vector_iterator& operator-=(int n) - { - m_i -= n; - return *this; - } - - WI_NODISCARD vector_iterator operator+(int n) const - { - vector_iterator ret(*this); - ret += n; - return ret; - } - - WI_NODISCARD vector_iterator operator-(int n) const - { - vector_iterator ret(*this); - ret -= n; - return ret; - } - - WI_NODISCARD ptrdiff_t operator-(const vector_iterator& other) const - { - return m_i - other.m_i; - } - - WI_NODISCARD bool operator==(const vector_iterator& other) const - { - return m_i == other.m_i; - } - - WI_NODISCARD bool operator!=(const vector_iterator& other) const - { - return m_i != other.m_i; - } - - WI_NODISCARD bool operator<(const vector_iterator& other) const - { - return m_i < other.m_i; - } - - WI_NODISCARD bool operator>(const vector_iterator& other) const - { - return m_i > other.m_i; - } - - WI_NODISCARD bool operator<=(const vector_iterator& other) const - { - return m_i <= other.m_i; - } - - WI_NODISCARD bool operator>=(const vector_iterator& other) const - { - return m_i >= other.m_i; - } - - private: - VectorType* m_v; // weak, collection must outlive iterators. - unsigned int m_i; - TSmart m_element; + private: + VectorType *m_v; // weak, collection must outlive iterators. }; - - vector_iterator begin() - { - return vector_iterator(m_v, 0); - } - - vector_iterator end() - { - unsigned int size; - err_policy::HResult(m_v->get_Size(&size)); - return vector_iterator(m_v, size); - } - -private: - VectorType* m_v; // weak, collection must outlive iterators. -}; #pragma endregion #pragma region error code based IVector<>/IVectorView<> -__WI_ITR_NAMESPACE_BEGIN + __WI_ITR_NAMESPACE_BEGIN -template -class vector_range_nothrow -{ -public: - typedef typename details::MapVectorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - vector_range_nothrow() = delete; - vector_range_nothrow(const vector_range_nothrow&) = delete; - vector_range_nothrow& operator=(const vector_range_nothrow&) = delete; - - vector_range_nothrow(vector_range_nothrow&& other) WI_NOEXCEPT : m_v(other.m_v), - m_size(other.m_size), - m_result(other.m_result), - m_resultStorage(other.m_resultStorage), - m_currentElement(wistd::move(other.m_currentElement)) + template class vector_range_nothrow { - } + public: + typedef typename details::MapVectorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; - vector_range_nothrow(_In_ VectorType* vector, HRESULT* result = nullptr) : - m_v(vector), m_result(result ? result : &m_resultStorage) - { - *m_result = m_v->get_Size(&m_size); - } + vector_range_nothrow() = delete; + vector_range_nothrow(const vector_range_nothrow &) = delete; + vector_range_nothrow &operator=(const vector_range_nothrow &) = delete; - class vector_iterator_nothrow - { - public: + vector_range_nothrow(vector_range_nothrow &&other) WI_NOEXCEPT + : m_v(other.m_v), + m_size(other.m_size), + m_result(other.m_result), + m_resultStorage(other.m_resultStorage), + m_currentElement(wistd::move(other.m_currentElement)) + { + } + + vector_range_nothrow(_In_ VectorType *vector, HRESULT *result = nullptr) + : m_v(vector), m_result(result ? result : &m_resultStorage) + { + *m_result = m_v->get_Size(&m_size); + } + + class vector_iterator_nothrow + { + public: #if WIL_USE_STL || defined(WIL_DOXYGEN) - // must be input_iterator_tag as use (via ++, --, etc.) of one invalidates the other. - typedef ::std::input_iterator_tag iterator_category; + // must be input_iterator_tag as use (via ++, --, etc.) of one invalidates the other. + typedef ::std::input_iterator_tag iterator_category; #endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart *pointer; + typedef const TSmart &reference; - vector_iterator_nothrow() = delete; - vector_iterator_nothrow(vector_range_nothrow* range, unsigned int pos) : - m_range(range), - m_i(pos) + vector_iterator_nothrow() = delete; + vector_iterator_nothrow(vector_range_nothrow *range, unsigned int pos) + : m_range(range), m_i(pos) #if WIL_ITERATOR_DEBUG_LEVEL > 0 - , - m_version(range->m_version) + , + m_version(range->m_version) #endif - { - } + { + } - WI_NODISCARD reference operator*() const - { - return *this->operator->(); - } + WI_NODISCARD reference operator*() const + { + return *this->operator->(); + } - WI_NODISCARD pointer operator->() const - { + WI_NODISCARD pointer operator->() const + { #if WIL_ITERATOR_DEBUG_LEVEL > 0 - WI_FAIL_FAST_ASSERT_MSG(m_version == m_range->m_version, "Dereferencing an out-of-date vector_iterator_nothrow"); - WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), "Dereferencing a vector_iterator_nothrow in a failed state"); - WI_FAIL_FAST_ASSERT_MSG(m_i < m_range->m_size, "Dereferencing an 'end' iterator"); + WI_FAIL_FAST_ASSERT_MSG(m_version == m_range->m_version, + "Dereferencing an out-of-date vector_iterator_nothrow"); + WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), + "Dereferencing a vector_iterator_nothrow in a failed state"); + WI_FAIL_FAST_ASSERT_MSG(m_i < m_range->m_size, "Dereferencing an 'end' iterator"); #endif - return wistd::addressof(m_range->m_currentElement); - } + return wistd::addressof(m_range->m_currentElement); + } - vector_iterator_nothrow& operator++() - { - return *this += 1; - } + vector_iterator_nothrow &operator++() + { + return *this += 1; + } - vector_iterator_nothrow& operator--() - { - return *this += -1; - } + vector_iterator_nothrow &operator--() + { + return *this += -1; + } - vector_iterator_nothrow operator++(int) - { - vector_iterator_nothrow old(*this); - ++*this; - return old; - } + vector_iterator_nothrow operator++(int) + { + vector_iterator_nothrow old(*this); + ++*this; + return old; + } - vector_iterator_nothrow operator--(int) - { - vector_iterator_nothrow old(*this); - --*this; - return old; - } + vector_iterator_nothrow operator--(int) + { + vector_iterator_nothrow old(*this); + --*this; + return old; + } - vector_iterator_nothrow& operator+=(int n) - { + vector_iterator_nothrow &operator+=(int n) + { #if WIL_ITERATOR_DEBUG_LEVEL == 2 - // This is _technically_ safe because we are not reading the out-of-date cached value, however having two active - // copies of iterators is generally a sign of problematic code with a bug waiting to happen - WI_FAIL_FAST_ASSERT_MSG( - m_version == m_range->m_version, "Incrementing/decrementing an out-of-date copy of a vector_iterator_nothrow"); + // This is _technically_ safe because we are not reading the out-of-date cached value, however having + // two active copies of iterators is generally a sign of problematic code with a bug waiting to happen + WI_FAIL_FAST_ASSERT_MSG(m_version == m_range->m_version, + "Incrementing/decrementing an out-of-date copy of a vector_iterator_nothrow"); #endif - m_i += n; + m_i += n; #if WIL_ITERATOR_DEBUG_LEVEL > 0 - // NOTE: 'm_i' is unsigned, hence the single check for increment/decrement - WI_FAIL_FAST_ASSERT_MSG(m_i <= m_range->m_size, "Incrementing/decrementing a vector_iterator_nothrow out of range"); + // NOTE: 'm_i' is unsigned, hence the single check for increment/decrement + WI_FAIL_FAST_ASSERT_MSG(m_i <= m_range->m_size, + "Incrementing/decrementing a vector_iterator_nothrow out of range"); #endif - m_range->get_at_current(m_i); + m_range->get_at_current(m_i); #if WIL_ITERATOR_DEBUG_LEVEL > 0 - m_version = m_range->m_version; + m_version = m_range->m_version; #endif - return *this; - } + return *this; + } - vector_iterator_nothrow& operator-=(int n) - { - return *this += -n; - } + vector_iterator_nothrow &operator-=(int n) + { + return *this += -n; + } - WI_NODISCARD bool operator==(vector_iterator_nothrow const& other) const - { - return FAILED(*m_range->m_result) || (m_i == other.m_i); - } + WI_NODISCARD bool operator==(vector_iterator_nothrow const &other) const + { + return FAILED(*m_range->m_result) || (m_i == other.m_i); + } - WI_NODISCARD bool operator!=(vector_iterator_nothrow const& other) const - { - return !operator==(other); - } + WI_NODISCARD bool operator!=(vector_iterator_nothrow const &other) const + { + return !operator==(other); + } - private: - vector_range_nothrow* m_range; - unsigned int m_i = 0; + private: + vector_range_nothrow *m_range; + unsigned int m_i = 0; #if WIL_ITERATOR_DEBUG_LEVEL > 0 - // For checked iterator support; must match the version in 'm_range' + // For checked iterator support; must match the version in 'm_range' + int m_version = 0; +#endif + }; + + vector_iterator_nothrow begin() + { + // NOTE: Calling 'begin()' more than once is explicitly allowed as a way to reset the range, however because + // state is shared between all iterators, this invalidates previously created iterators + get_at_current(0); + return vector_iterator_nothrow(this, 0); + } + + vector_iterator_nothrow end() + { + return vector_iterator_nothrow(this, m_size); + } + + // Note, the error code is observed in operator!= and operator==, it always + // returns "equal" in the failed state to force the compare to the end + // iterator to return false and stop the loop. + // + // Is this ok for the general case? + void get_at_current(unsigned int i) + { + if (SUCCEEDED(*m_result) && (i < m_size)) + { + *m_result = m_v->GetAt(i, m_currentElement.ReleaseAndGetAddressOf()); + +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + ++m_version; +#endif + } + } + + private: + VectorType *m_v; // weak, collection must outlive iterators. + unsigned int m_size; + + // This state is shared by vector_iterator_nothrow instances. this means + // use of one iterator invalidates the other. + HRESULT *m_result; + HRESULT m_resultStorage = + S_OK; // for the case where the caller does not provide the location to store the result + TSmart m_currentElement; + +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + // For checked iterator support int m_version = 0; #endif }; - vector_iterator_nothrow begin() - { - // NOTE: Calling 'begin()' more than once is explicitly allowed as a way to reset the range, however because state is - // shared between all iterators, this invalidates previously created iterators - get_at_current(0); - return vector_iterator_nothrow(this, 0); - } - - vector_iterator_nothrow end() - { - return vector_iterator_nothrow(this, m_size); - } - - // Note, the error code is observed in operator!= and operator==, it always - // returns "equal" in the failed state to force the compare to the end - // iterator to return false and stop the loop. - // - // Is this ok for the general case? - void get_at_current(unsigned int i) - { - if (SUCCEEDED(*m_result) && (i < m_size)) - { - *m_result = m_v->GetAt(i, m_currentElement.ReleaseAndGetAddressOf()); - -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - ++m_version; -#endif - } - } - -private: - VectorType* m_v; // weak, collection must outlive iterators. - unsigned int m_size; - - // This state is shared by vector_iterator_nothrow instances. this means - // use of one iterator invalidates the other. - HRESULT* m_result; - HRESULT m_resultStorage = S_OK; // for the case where the caller does not provide the location to store the result - TSmart m_currentElement; - -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - // For checked iterator support - int m_version = 0; -#endif -}; - -__WI_ITR_NAMESPACE_END + __WI_ITR_NAMESPACE_END #pragma endregion #pragma region exception and fail fast based IIterable<> -template -class iterable_range -{ -public: - typedef typename details::MapIteratorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - explicit iterable_range(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) : m_iterable(iterable) + template class iterable_range { - } + public: + typedef typename details::MapIteratorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; - class iterable_iterator - { - public: + explicit iterable_range(_In_ ABI::Windows::Foundation::Collections::IIterable *iterable) + : m_iterable(iterable) + { + } + + class iterable_iterator + { + public: #if WIL_USE_STL || defined(WIL_DOXYGEN) - typedef ::std::forward_iterator_tag iterator_category; + typedef ::std::forward_iterator_tag iterator_category; #endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart *pointer; + typedef const TSmart &reference; - iterable_iterator() : m_i(-1) - { - } + iterable_iterator() : m_i(-1) + { + } - // for begin() - explicit iterable_iterator(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) - { - err_policy::HResult(iterable->First(&m_iterator)); - boolean hasCurrent; - err_policy::HResult(m_iterator->get_HasCurrent(&hasCurrent)); - m_i = hasCurrent ? 0 : -1; - } + // for begin() + explicit iterable_iterator(_In_ ABI::Windows::Foundation::Collections::IIterable *iterable) + { + err_policy::HResult(iterable->First(&m_iterator)); + boolean hasCurrent; + err_policy::HResult(m_iterator->get_HasCurrent(&hasCurrent)); + m_i = hasCurrent ? 0 : -1; + } - // for end() - iterable_iterator(int /*currentIndex*/) : m_i(-1) - { - } + // for end() + iterable_iterator(int /*currentIndex*/) : m_i(-1) + { + } - iterable_iterator(const iterable_iterator& other) - { - m_iterator = other.m_iterator; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); - } - - iterable_iterator& operator=(const iterable_iterator& other) - { - if (this != wistd::addressof(other)) + iterable_iterator(const iterable_iterator &other) { m_iterator = other.m_iterator; m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); + err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); } - return *this; - } - WI_NODISCARD bool operator==(iterable_iterator const& other) const - { - return m_i == other.m_i; - } - - WI_NODISCARD bool operator!=(iterable_iterator const& other) const - { - return !operator==(other); - } - - reference operator*() - { - err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); - return m_element; - } - - pointer operator->() - { - err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); - return wistd::addressof(m_element); - } - - iterable_iterator& operator++() - { - boolean hasCurrent; - err_policy::HResult(m_iterator->MoveNext(&hasCurrent)); - if (hasCurrent) + iterable_iterator &operator=(const iterable_iterator &other) { - m_i++; - } - else - { - m_i = -1; - } - return *this; - } - - iterable_iterator operator++(int) - { - iterable_iterator old(*this); - ++*this; - return old; - } - - private: - Microsoft::WRL::ComPtr> m_iterator; - int m_i; - TSmart m_element; - }; - - iterable_iterator begin() - { - return iterable_iterator(m_iterable); - } - - iterable_iterator end() - { - return iterable_iterator(); - } - -private: - // weak, collection must outlive iterators. - ABI::Windows::Foundation::Collections::IIterable* m_iterable; -}; -#pragma endregion - -#if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) -/** Converts WinRT vectors to std::vector by requesting the collection's data in a single -operation. This can be more efficient in terms of IPC cost than iteratively processing it. -@code -ComPtr> values = GetValues(); -std::vector> allData = wil::to_vector(values); -for (ComPtr const& item : allData) -{ - // use item -} -@endcode -Can be used for ABI::Windows::Foundation::Collections::IVector and -ABI::Windows::Foundation::Collections::IVectorView -*/ -template -auto to_vector(VectorType* src) -{ - using TResult = typename details::MapVectorResultType::type; - using TSmart = typename details::MapToSmartType::type; - static_assert(sizeof(TResult) == sizeof(TSmart), "result and smart sizes are different"); - std::vector output; - UINT32 expected = 0; - THROW_IF_FAILED(src->get_Size(&expected)); - if (expected > 0) - { - output.resize(expected + 1); - UINT32 fetched = 0; - THROW_IF_FAILED(src->GetMany(0, static_cast(output.size()), reinterpret_cast(output.data()), &fetched)); - THROW_HR_IF(E_CHANGED_STATE, fetched > expected); - output.resize(fetched); - } - return output; -} -#endif - -#pragma region error code base IIterable<> - -__WI_ITR_NAMESPACE_BEGIN - -template -class iterable_range_nothrow -{ -public: - typedef typename details::MapIteratorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - iterable_range_nothrow() = delete; - iterable_range_nothrow(const iterable_range_nothrow&) = delete; - iterable_range_nothrow& operator=(const iterable_range_nothrow&) = delete; - iterable_range_nothrow& operator=(iterable_range_nothrow&&) = delete; - - iterable_range_nothrow(iterable_range_nothrow&& other) WI_NOEXCEPT : m_iterator(wistd::move(other.m_iterator)), - m_element(wistd::move(other.m_element)), - m_resultStorage(other.m_resultStorage) -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - , - m_index(other.m_index) -#endif - { - if (other.m_result == &other.m_resultStorage) - { - m_result = &m_resultStorage; - } - else - { - m_result = other.m_result; - } - } - - iterable_range_nothrow(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable, HRESULT* result = nullptr) : - m_result(result ? result : &m_resultStorage) - { - *m_result = iterable->First(&m_iterator); - if (SUCCEEDED(*m_result)) - { - boolean hasCurrent; - *m_result = m_iterator->get_HasCurrent(&hasCurrent); - if (SUCCEEDED(*m_result) && hasCurrent) - { - *m_result = m_iterator->get_Current(m_element.ReleaseAndGetAddressOf()); - if (FAILED(*m_result)) + if (this != wistd::addressof(other)) { - m_iterator = nullptr; // release the iterator if no elements are found + m_iterator = other.m_iterator; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); } + return *this; } - else + + WI_NODISCARD bool operator==(iterable_iterator const &other) const { - m_iterator = nullptr; // release the iterator if no elements are found + return m_i == other.m_i; } - } - } - class iterable_iterator_nothrow - { - public: -#if WIL_USE_STL || defined(WIL_DOXYGEN) - // muse be input_iterator_tag as use of one instance invalidates the other. - typedef ::std::input_iterator_tag iterator_category; -#endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; - - iterable_iterator_nothrow(_In_ iterable_range_nothrow* range, int currentIndex) : m_range(range), m_i(currentIndex) - { - } - - WI_NODISCARD bool operator==(iterable_iterator_nothrow const& other) const - { - return FAILED(*m_range->m_result) || (m_i == other.m_i); - } - - WI_NODISCARD bool operator!=(iterable_iterator_nothrow const& other) const - { - return !operator==(other); - } - - WI_NODISCARD reference operator*() const WI_NOEXCEPT - { - return *this->operator->(); - } - - WI_NODISCARD pointer operator->() const WI_NOEXCEPT - { -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), "Dereferencing an iterable_iterator_nothrow in a failed state"); - WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Dereferencing an 'end' iterator"); - WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, "Dereferencing an out-of-date iterable_iterator_nothrow"); -#endif - return wistd::addressof(m_range->m_element); - } - - iterable_iterator_nothrow& operator++() - { -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - // Failing this check is always bad because the iterator object we hold always advances forward - WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Incrementing an end iterator"); - WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, "Incrementing an out-of-date copy of an iterable_iterator_nothrow"); -#endif - boolean hasCurrent; - *m_range->m_result = m_range->m_iterator->MoveNext(&hasCurrent); - if (SUCCEEDED(*m_range->m_result) && hasCurrent) + WI_NODISCARD bool operator!=(iterable_iterator const &other) const { - *m_range->m_result = m_range->m_iterator->get_Current(m_range->m_element.ReleaseAndGetAddressOf()); - if (SUCCEEDED(*m_range->m_result)) + return !operator==(other); + } + + reference operator*() + { + err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); + return m_element; + } + + pointer operator->() + { + err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); + return wistd::addressof(m_element); + } + + iterable_iterator &operator++() + { + boolean hasCurrent; + err_policy::HResult(m_iterator->MoveNext(&hasCurrent)); + if (hasCurrent) { m_i++; } @@ -1214,124 +1035,315 @@ public: { m_i = -1; } + return *this; + } + + iterable_iterator operator++(int) + { + iterable_iterator old(*this); + ++*this; + return old; + } + + private: + Microsoft::WRL::ComPtr> m_iterator; + int m_i; + TSmart m_element; + }; + + iterable_iterator begin() + { + return iterable_iterator(m_iterable); + } + + iterable_iterator end() + { + return iterable_iterator(); + } + + private: + // weak, collection must outlive iterators. + ABI::Windows::Foundation::Collections::IIterable *m_iterable; + }; +#pragma endregion + +#if (WIL_USE_STL && defined(WIL_ENABLE_EXCEPTIONS)) || defined(WIL_DOXYGEN) + /** Converts WinRT vectors to std::vector by requesting the collection's data in a single + operation. This can be more efficient in terms of IPC cost than iteratively processing it. + @code + ComPtr> values = GetValues(); + std::vector> allData = wil::to_vector(values); + for (ComPtr const& item : allData) + { + // use item + } + @endcode + Can be used for ABI::Windows::Foundation::Collections::IVector and + ABI::Windows::Foundation::Collections::IVectorView + */ + template auto to_vector(VectorType *src) + { + using TResult = typename details::MapVectorResultType::type; + using TSmart = typename details::MapToSmartType::type; + static_assert(sizeof(TResult) == sizeof(TSmart), "result and smart sizes are different"); + std::vector output; + UINT32 expected = 0; + THROW_IF_FAILED(src->get_Size(&expected)); + if (expected > 0) + { + output.resize(expected + 1); + UINT32 fetched = 0; + THROW_IF_FAILED(src->GetMany(0, static_cast(output.size()), + reinterpret_cast(output.data()), &fetched)); + THROW_HR_IF(E_CHANGED_STATE, fetched > expected); + output.resize(fetched); + } + return output; + } +#endif + +#pragma region error code base IIterable<> + + __WI_ITR_NAMESPACE_BEGIN + + template class iterable_range_nothrow + { + public: + typedef typename details::MapIteratorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; + + iterable_range_nothrow() = delete; + iterable_range_nothrow(const iterable_range_nothrow &) = delete; + iterable_range_nothrow &operator=(const iterable_range_nothrow &) = delete; + iterable_range_nothrow &operator=(iterable_range_nothrow &&) = delete; + + iterable_range_nothrow(iterable_range_nothrow &&other) WI_NOEXCEPT : m_iterator(wistd::move(other.m_iterator)), + m_element(wistd::move(other.m_element)), + m_resultStorage(other.m_resultStorage) +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + , + m_index(other.m_index) +#endif + { + if (other.m_result == &other.m_resultStorage) + { + m_result = &m_resultStorage; } else { - m_i = -1; + m_result = other.m_result; } -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - m_range->m_index = m_i; -#endif - return *this; } - iterable_iterator_nothrow operator++(int) + iterable_range_nothrow(_In_ ABI::Windows::Foundation::Collections::IIterable *iterable, + HRESULT *result = nullptr) + : m_result(result ? result : &m_resultStorage) { - iterable_iterator_nothrow old(*this); - ++*this; - return old; + *m_result = iterable->First(&m_iterator); + if (SUCCEEDED(*m_result)) + { + boolean hasCurrent; + *m_result = m_iterator->get_HasCurrent(&hasCurrent); + if (SUCCEEDED(*m_result) && hasCurrent) + { + *m_result = m_iterator->get_Current(m_element.ReleaseAndGetAddressOf()); + if (FAILED(*m_result)) + { + m_iterator = nullptr; // release the iterator if no elements are found + } + } + else + { + m_iterator = nullptr; // release the iterator if no elements are found + } + } } - private: - iterable_range_nothrow* m_range; - int m_i; + class iterable_iterator_nothrow + { + public: +#if WIL_USE_STL || defined(WIL_DOXYGEN) + // muse be input_iterator_tag as use of one instance invalidates the other. + typedef ::std::input_iterator_tag iterator_category; +#endif + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart *pointer; + typedef const TSmart &reference; + + iterable_iterator_nothrow(_In_ iterable_range_nothrow *range, int currentIndex) + : m_range(range), m_i(currentIndex) + { + } + + WI_NODISCARD bool operator==(iterable_iterator_nothrow const &other) const + { + return FAILED(*m_range->m_result) || (m_i == other.m_i); + } + + WI_NODISCARD bool operator!=(iterable_iterator_nothrow const &other) const + { + return !operator==(other); + } + + WI_NODISCARD reference operator*() const WI_NOEXCEPT + { + return *this->operator->(); + } + + WI_NODISCARD pointer operator->() const WI_NOEXCEPT + { +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + WI_FAIL_FAST_ASSERT_MSG(SUCCEEDED(*m_range->m_result), + "Dereferencing an iterable_iterator_nothrow in a failed state"); + WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Dereferencing an 'end' iterator"); + WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, + "Dereferencing an out-of-date iterable_iterator_nothrow"); +#endif + return wistd::addressof(m_range->m_element); + } + + iterable_iterator_nothrow &operator++() + { +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + // Failing this check is always bad because the iterator object we hold always advances forward + WI_FAIL_FAST_ASSERT_MSG(m_i >= 0, "Incrementing an end iterator"); + WI_FAIL_FAST_ASSERT_MSG(m_i == m_range->m_index, + "Incrementing an out-of-date copy of an iterable_iterator_nothrow"); +#endif + boolean hasCurrent; + *m_range->m_result = m_range->m_iterator->MoveNext(&hasCurrent); + if (SUCCEEDED(*m_range->m_result) && hasCurrent) + { + *m_range->m_result = m_range->m_iterator->get_Current(m_range->m_element.ReleaseAndGetAddressOf()); + if (SUCCEEDED(*m_range->m_result)) + { + m_i++; + } + else + { + m_i = -1; + } + } + else + { + m_i = -1; + } +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + m_range->m_index = m_i; +#endif + return *this; + } + + iterable_iterator_nothrow operator++(int) + { + iterable_iterator_nothrow old(*this); + ++*this; + return old; + } + + private: + iterable_range_nothrow *m_range; + int m_i; + }; + + iterable_iterator_nothrow begin() + { +#if WIL_ITERATOR_DEBUG_LEVEL == 2 + // The IIterator we hold only advances forward; we can't reset it back to the beginning. Calling this method + // more than once will very likely lead to unexpected behavior. + WI_FAIL_FAST_ASSERT_MSG(m_index == 0, "Calling begin() on an already advanced iterable_range_nothrow"); +#endif + return iterable_iterator_nothrow(this, this->m_iterator ? 0 : -1); + } + + iterable_iterator_nothrow end() + { + return iterable_iterator_nothrow(this, -1); + } + + private: + Microsoft::WRL::ComPtr> m_iterator; + // This state is shared by all iterator instances + // so use of one iterator can invalidate another's ability to dereference + // that is allowed for input iterators. + TSmart m_element; + HRESULT *m_result; + HRESULT m_resultStorage = S_OK; + +#if WIL_ITERATOR_DEBUG_LEVEL > 0 + // For checked iterator support + int m_index = 0; +#endif }; - iterable_iterator_nothrow begin() - { -#if WIL_ITERATOR_DEBUG_LEVEL == 2 - // The IIterator we hold only advances forward; we can't reset it back to the beginning. Calling this method more than - // once will very likely lead to unexpected behavior. - WI_FAIL_FAST_ASSERT_MSG(m_index == 0, "Calling begin() on an already advanced iterable_range_nothrow"); -#endif - return iterable_iterator_nothrow(this, this->m_iterator ? 0 : -1); - } - - iterable_iterator_nothrow end() - { - return iterable_iterator_nothrow(this, -1); - } - -private: - Microsoft::WRL::ComPtr> m_iterator; - // This state is shared by all iterator instances - // so use of one iterator can invalidate another's ability to dereference - // that is allowed for input iterators. - TSmart m_element; - HRESULT* m_result; - HRESULT m_resultStorage = S_OK; - -#if WIL_ITERATOR_DEBUG_LEVEL > 0 - // For checked iterator support - int m_index = 0; -#endif -}; - -__WI_ITR_NAMESPACE_END + __WI_ITR_NAMESPACE_END #pragma endregion #ifdef WIL_ENABLE_EXCEPTIONS -template -vector_range> get_range(ABI::Windows::Foundation::Collections::IVector* v) -{ - return vector_range>(v); -} + template + vector_range> get_range( + ABI::Windows::Foundation::Collections::IVector *v) + { + return vector_range>(v); + } -template -vector_range> get_range(ABI::Windows::Foundation::Collections::IVectorView* v) -{ - return vector_range>(v); -} + template + vector_range> get_range( + ABI::Windows::Foundation::Collections::IVectorView *v) + { + return vector_range>(v); + } #endif // WIL_ENABLE_EXCEPTIONS -template -vector_range, err_failfast_policy> get_range_failfast( - ABI::Windows::Foundation::Collections::IVector* v) -{ - return vector_range, err_failfast_policy>(v); -} + template + vector_range, err_failfast_policy> get_range_failfast( + ABI::Windows::Foundation::Collections::IVector *v) + { + return vector_range, err_failfast_policy>(v); + } -template -vector_range, err_failfast_policy> get_range_failfast( - ABI::Windows::Foundation::Collections::IVectorView* v) -{ - return vector_range, err_failfast_policy>(v); -} + template + vector_range, err_failfast_policy> get_range_failfast( + ABI::Windows::Foundation::Collections::IVectorView *v) + { + return vector_range, err_failfast_policy>(v); + } -template -vector_range_nothrow> get_range_nothrow( - ABI::Windows::Foundation::Collections::IVector* v, HRESULT* result = nullptr) -{ - return vector_range_nothrow>(v, result); -} + template + vector_range_nothrow> get_range_nothrow( + ABI::Windows::Foundation::Collections::IVector *v, HRESULT *result = nullptr) + { + return vector_range_nothrow>(v, result); + } -template -vector_range_nothrow> get_range_nothrow( - ABI::Windows::Foundation::Collections::IVectorView* v, HRESULT* result = nullptr) -{ - return vector_range_nothrow>(v, result); -} + template + vector_range_nothrow> get_range_nothrow( + ABI::Windows::Foundation::Collections::IVectorView *v, HRESULT *result = nullptr) + { + return vector_range_nothrow>(v, result); + } #ifdef WIL_ENABLE_EXCEPTIONS -template -iterable_range get_range(ABI::Windows::Foundation::Collections::IIterable* v) -{ - return iterable_range(v); -} + template iterable_range get_range(ABI::Windows::Foundation::Collections::IIterable *v) + { + return iterable_range(v); + } #endif // WIL_ENABLE_EXCEPTIONS -template -iterable_range get_range_failfast(ABI::Windows::Foundation::Collections::IIterable* v) -{ - return iterable_range(v); -} + template + iterable_range get_range_failfast(ABI::Windows::Foundation::Collections::IIterable *v) + { + return iterable_range(v); + } -template -iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collections::IIterable* v, HRESULT* result = nullptr) -{ - return iterable_range_nothrow(v, result); -} + template + iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collections::IIterable *v, + HRESULT *result = nullptr) + { + return iterable_range_nothrow(v, result); + } #pragma endregion } // namespace wil @@ -1342,54 +1354,49 @@ iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collection namespace ABI { #endif -namespace Windows -{ - namespace Foundation + namespace Windows { - namespace Collections + namespace Foundation { - template - typename wil::vector_range>::vector_iterator begin(IVector* v) + namespace Collections { - return typename wil::vector_range>::vector_iterator(v, 0); - } + template typename wil::vector_range>::vector_iterator begin(IVector *v) + { + return typename wil::vector_range>::vector_iterator(v, 0); + } - template - typename wil::vector_range>::vector_iterator end(IVector* v) - { - unsigned int size; - THROW_IF_FAILED(v->get_Size(&size)); - return typename wil::vector_range>::vector_iterator(v, size); - } + template typename wil::vector_range>::vector_iterator end(IVector *v) + { + unsigned int size; + THROW_IF_FAILED(v->get_Size(&size)); + return typename wil::vector_range>::vector_iterator(v, size); + } - template - typename wil::vector_range>::vector_iterator begin(IVectorView* v) - { - return typename wil::vector_range>::vector_iterator(v, 0); - } + template + typename wil::vector_range>::vector_iterator begin(IVectorView *v) + { + return typename wil::vector_range>::vector_iterator(v, 0); + } - template - typename wil::vector_range>::vector_iterator end(IVectorView* v) - { - unsigned int size; - THROW_IF_FAILED(v->get_Size(&size)); - return typename wil::vector_range>::vector_iterator(v, size); - } + template typename wil::vector_range>::vector_iterator end(IVectorView *v) + { + unsigned int size; + THROW_IF_FAILED(v->get_Size(&size)); + return typename wil::vector_range>::vector_iterator(v, size); + } - template - typename wil::iterable_range::iterable_iterator begin(IIterable* i) - { - return typename wil::iterable_range::iterable_iterator(i); - } + template typename wil::iterable_range::iterable_iterator begin(IIterable *i) + { + return typename wil::iterable_range::iterable_iterator(i); + } - template - typename wil::iterable_range::iterable_iterator end(IIterable*) - { - return typename wil::iterable_range::iterable_iterator(); - } - } // namespace Collections - } // namespace Foundation -} // namespace Windows + template typename wil::iterable_range::iterable_iterator end(IIterable *) + { + return typename wil::iterable_range::iterable_iterator(); + } + } // namespace Collections + } // namespace Foundation + } // namespace Windows #if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) } // namespace ABI #endif @@ -1401,450 +1408,474 @@ namespace wil { #pragma region WinRT Async API helpers -/// @cond -namespace details -{ - template ::value, int>::type = 0> - HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) + /// @cond + namespace details { - return wistd::forward(func)(wistd::forward(args)...); - } + template ::value, int>::type = 0> + HRESULT CallAndHandleErrorsWithReturnType(TFunc &&func, Args &&...args) + { + return wistd::forward(func)(wistd::forward(args)...); + } #ifdef WIL_ENABLE_EXCEPTIONS - template ::value, int>::type = 0> - HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) - { - try + template ::value, int>::type = 0> + HRESULT CallAndHandleErrorsWithReturnType(TFunc &&func, Args &&...args) { - wistd::forward(func)(wistd::forward(args)...); - } - CATCH_RETURN(); - return S_OK; - } -#endif - - template - HRESULT CallAndHandleErrors(TFunc&& func, Args&&... args) - { - return CallAndHandleErrorsWithReturnType(func)(wistd::forward(args)...))>( - wistd::forward(func), wistd::forward(args)...); - } - - // Get the last type of a template parameter pack. - // usage: - // LastType::type boolValue; - template - struct LastType - { - template - struct LastTypeOfTs - { - typedef typename LastTypeOfTs::type type; - }; - - template - struct LastTypeOfTs - { - typedef T type; - }; - - template - static typename LastTypeOfTs::type LastTypeOfTsFunc() - { - } - typedef decltype(LastTypeOfTsFunc()) type; - }; - - // Takes a member function that has an out param like F(..., IAsyncAction**) or F(..., IAsyncOperation**) - // and returns IAsyncAction* or IAsyncOperation*. - template - typename wistd::remove_pointer::type>::type GetReturnParamPointerType(HRESULT (STDMETHODCALLTYPE I::*)(P...)); - - // Use to determine the result type of the async action/operation interfaces or example - // decltype(GetAsyncResultType(action.get())) returns void - void GetAsyncResultType(ABI::Windows::Foundation::IAsyncAction*); - template - void GetAsyncResultType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); - template - typename wil::details::MapAsyncOpResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperation*); - template - typename wil::details::MapAsyncOpProgressResultType::type GetAsyncResultType( - ABI::Windows::Foundation::IAsyncOperationWithProgress*); - - // Use to determine the result type of the async action/operation interfaces or example - // decltype(GetAsyncDelegateType(action.get())) returns void - ABI::Windows::Foundation::IAsyncActionCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncAction*); - template - ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler

* GetAsyncDelegateType( - ABI::Windows::Foundation::IAsyncActionWithProgress

*); - template - ABI::Windows::Foundation::IAsyncOperationCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperation*); - template - ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler* GetAsyncDelegateType( - ABI::Windows::Foundation::IAsyncOperationWithProgress*); - - template - HRESULT RunWhenCompleteAction(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT - { - using namespace Microsoft::WRL; - typedef wistd::remove_pointer_t TIDelegate; - - auto callback = Callback, TIDelegate, TBaseAgility>>( - [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { - HRESULT hr = S_OK; - if (status != ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully - { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) - { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); - if (SUCCEEDED(hr)) - { - // Return the operations error code to the caller. - hr = errorCode; - } - } - } - - return CallAndHandleErrors(func, hr); - }); - RETURN_IF_NULL_ALLOC(callback); - return operation->put_Completed(callback.Get()); - } - - template - HRESULT RunWhenComplete(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT - { - using namespace Microsoft::WRL; - using namespace ABI::Windows::Foundation::Internal; - - typedef wistd::remove_pointer_t TIDelegate; - - auto callback = Callback, TIDelegate, TBaseAgility>>( - [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { - typename details::MapToSmartType::type::TResult_complex>::type>::type result; - - HRESULT hr = S_OK; - // avoid a potentially costly marshaled QI / call if we completed successfully - if (status == ABI::Windows::Foundation::AsyncStatus::Completed) - { - hr = operation->GetResults(result.GetAddressOf()); - } - else - { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) - { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); - if (SUCCEEDED(hr)) - { - // Return the operations error code to the caller. - hr = errorCode; - } - } - } - - return CallAndHandleErrors(func, hr, result.Get()); - }); - RETURN_IF_NULL_ALLOC(callback); - return operation->put_Completed(callback.Get()); - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - template - HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT - { - typedef wistd::remove_pointer_t TIDelegate; - - class CompletionDelegate - : public Microsoft::WRL::RuntimeClass, TIDelegate, Microsoft::WRL::FtmBase> - { - public: - HRESULT RuntimeClassInitialize() + try { - RETURN_HR(m_completedEventHandle.create()); + wistd::forward(func)(wistd::forward(args)...); } - - HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override - { - m_status = status; - m_completedEventHandle.SetEvent(); - return S_OK; - } - - WI_NODISCARD HANDLE GetEvent() const - { - return m_completedEventHandle.get(); - } - - WI_NODISCARD ABI::Windows::Foundation::AsyncStatus GetStatus() const - { - return m_status; - } - - private: - volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started; - wil::unique_event_nothrow m_completedEventHandle; - }; - - WI_ASSERT(timedOut || (timeoutValue == INFINITE)); - assign_to_opt_param(timedOut, false); - - Microsoft::WRL::ComPtr completedDelegate; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&completedDelegate)); - RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get())); - - HANDLE handles[] = {completedDelegate->GetEvent()}; - DWORD dwHandleIndex; - HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex); - - // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. Otherwise, fail. - if (timedOut && (hr == RPC_S_CALLPENDING)) - { - *timedOut = true; + CATCH_RETURN(); return S_OK; } - RETURN_IF_FAILED(hr); +#endif - if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed) + template HRESULT CallAndHandleErrors(TFunc &&func, Args &&...args) { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - Microsoft::WRL::ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) + return CallAndHandleErrorsWithReturnType(func)( + wistd::forward(args)...))>(wistd::forward(func), wistd::forward(args)...); + } + + // Get the last type of a template parameter pack. + // usage: + // LastType::type boolValue; + template struct LastType + { + template struct LastTypeOfTs { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); + typedef typename LastTypeOfTs::type type; + }; + + template struct LastTypeOfTs + { + typedef T type; + }; + + template static typename LastTypeOfTs::type LastTypeOfTsFunc() + { + } + typedef decltype(LastTypeOfTsFunc()) type; + }; + + // Takes a member function that has an out param like F(..., IAsyncAction**) or F(..., IAsyncOperation**) + // and returns IAsyncAction* or IAsyncOperation*. + template + typename wistd::remove_pointer::type>::type GetReturnParamPointerType( + HRESULT (STDMETHODCALLTYPE I::*)(P...)); + + // Use to determine the result type of the async action/operation interfaces or example + // decltype(GetAsyncResultType(action.get())) returns void + void GetAsyncResultType(ABI::Windows::Foundation::IAsyncAction *); + template void GetAsyncResultType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); + template + typename wil::details::MapAsyncOpResultType::type GetAsyncResultType( + ABI::Windows::Foundation::IAsyncOperation *); + template + typename wil::details::MapAsyncOpProgressResultType::type GetAsyncResultType( + ABI::Windows::Foundation::IAsyncOperationWithProgress *); + + // Use to determine the result type of the async action/operation interfaces or example + // decltype(GetAsyncDelegateType(action.get())) returns void + ABI::Windows::Foundation::IAsyncActionCompletedHandler *GetAsyncDelegateType( + ABI::Windows::Foundation::IAsyncAction *); + template + ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler

*GetAsyncDelegateType( + ABI::Windows::Foundation::IAsyncActionWithProgress

*); + template + ABI::Windows::Foundation::IAsyncOperationCompletedHandler *GetAsyncDelegateType( + ABI::Windows::Foundation::IAsyncOperation *); + template + ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler *GetAsyncDelegateType( + ABI::Windows::Foundation::IAsyncOperationWithProgress *); + + template + HRESULT RunWhenCompleteAction(_In_ TIOperation operation, TFunction &&func) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + typedef wistd::remove_pointer_t TIDelegate; + + auto callback = Callback, TIDelegate, TBaseAgility>>( + [func = wistd::forward(func)]( + TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { + HRESULT hr = S_OK; + if (status != + ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / + // call if we completed successfully + { + // QI to the IAsyncInfo interface. While all operations implement this, it is + // possible that the stub has disconnected, causing the QI to fail. + ComPtr asyncInfo; + hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); + if (SUCCEEDED(hr)) + { + // Save the error code result in a temporary variable to allow us + // to also retrieve the result of the COM call. If the stub has + // disconnected, this call may fail. + HRESULT errorCode = E_UNEXPECTED; + hr = asyncInfo->get_ErrorCode(&errorCode); + if (SUCCEEDED(hr)) + { + // Return the operations error code to the caller. + hr = errorCode; + } + } + } + + return CallAndHandleErrors(func, hr); + }); + RETURN_IF_NULL_ALLOC(callback); + return operation->put_Completed(callback.Get()); + } + + template + HRESULT RunWhenComplete(_In_ TIOperation operation, TFunction &&func) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + using namespace ABI::Windows::Foundation::Internal; + + typedef wistd::remove_pointer_t TIDelegate; + + auto callback = Callback, TIDelegate, TBaseAgility>>( + [func = wistd::forward(func)]( + TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT { + typename details::MapToSmartType::type::TResult_complex>::type>::type result; + + HRESULT hr = S_OK; + // avoid a potentially costly marshaled QI / call if we completed successfully + if (status == ABI::Windows::Foundation::AsyncStatus::Completed) + { + hr = operation->GetResults(result.GetAddressOf()); + } + else + { + // QI to the IAsyncInfo interface. While all operations implement this, it is + // possible that the stub has disconnected, causing the QI to fail. + ComPtr asyncInfo; + hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); + if (SUCCEEDED(hr)) + { + // Save the error code result in a temporary variable to allow us + // to also retrieve the result of the COM call. If the stub has + // disconnected, this call may fail. + HRESULT errorCode = E_UNEXPECTED; + hr = asyncInfo->get_ErrorCode(&errorCode); + if (SUCCEEDED(hr)) + { + // Return the operations error code to the caller. + hr = errorCode; + } + } + } + + return CallAndHandleErrors(func, hr, result.Get()); + }); + RETURN_IF_NULL_ALLOC(callback); + return operation->put_Completed(callback.Get()); + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + template + HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, + _Out_opt_ bool *timedOut) WI_NOEXCEPT + { + typedef wistd::remove_pointer_t TIDelegate; + + class CompletionDelegate + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, TIDelegate, + Microsoft::WRL::FtmBase> + { + public: + HRESULT RuntimeClassInitialize() + { + RETURN_HR(m_completedEventHandle.create()); + } + + HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, + ABI::Windows::Foundation::AsyncStatus status) override + { + m_status = status; + m_completedEventHandle.SetEvent(); + return S_OK; + } + + WI_NODISCARD HANDLE GetEvent() const + { + return m_completedEventHandle.get(); + } + + WI_NODISCARD ABI::Windows::Foundation::AsyncStatus GetStatus() const + { + return m_status; + } + + private: + volatile ABI::Windows::Foundation::AsyncStatus m_status = + ABI::Windows::Foundation::AsyncStatus::Started; + wil::unique_event_nothrow m_completedEventHandle; + }; + + WI_ASSERT(timedOut || (timeoutValue == INFINITE)); + assign_to_opt_param(timedOut, false); + + Microsoft::WRL::ComPtr completedDelegate; + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&completedDelegate)); + RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get())); + + HANDLE handles[] = {completedDelegate->GetEvent()}; + DWORD dwHandleIndex; + HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex); + + // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. + // Otherwise, fail. + if (timedOut && (hr == RPC_S_CALLPENDING)) + { + *timedOut = true; + return S_OK; + } + RETURN_IF_FAILED(hr); + + if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed) + { + // QI to the IAsyncInfo interface. While all operations implement this, it is + // possible that the stub has disconnected, causing the QI to fail. + Microsoft::WRL::ComPtr asyncInfo; + hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); if (SUCCEEDED(hr)) { - // Return the operations error code to the caller. - hr = errorCode; + // Save the error code result in a temporary variable to allow us + // to also retrieve the result of the COM call. If the stub has + // disconnected, this call may fail. + HRESULT errorCode = E_UNEXPECTED; + hr = asyncInfo->get_ErrorCode(&errorCode); + if (SUCCEEDED(hr)) + { + // Return the operations error code to the caller. + hr = errorCode; + } } + return hr; // leave it to the caller to log failures. } - return hr; // leave it to the caller to log failures. + return S_OK; } - return S_OK; - } - template - HRESULT WaitForCompletion(_In_ TIOperation operation, _Out_ TIResults result, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT - { - RETURN_IF_FAILED_EXPECTED(details::WaitForCompletion(operation, flags, timeoutValue, timedOut)); - return operation->GetResults(result); - } + template + HRESULT WaitForCompletion(_In_ TIOperation operation, _Out_ TIResults result, COWAIT_FLAGS flags, + DWORD timeoutValue, _Out_opt_ bool *timedOut) WI_NOEXCEPT + { + RETURN_IF_FAILED_EXPECTED(details::WaitForCompletion(operation, flags, timeoutValue, timedOut)); + return operation->GetResults(result); + } #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -} // namespace details -/// @endcond + } // namespace details + /// @endcond -/** Set the completion callback for an async operation to run a caller provided function. -Once complete the function is called with the error code result of the operation -and the async operation result (if applicable). -The function parameter list must be (HRESULT hr) for actions, -(HRESULT hr, IResultInterface* object) for operations that produce interfaces, -and (HRESULT hr, TResult value) for operations that produce value types. -~~~ -run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void -{ + /** Set the completion callback for an async operation to run a caller provided function. + Once complete the function is called with the error code result of the operation + and the async operation result (if applicable). + The function parameter list must be (HRESULT hr) for actions, + (HRESULT hr, IResultInterface* object) for operations that produce interfaces, + and (HRESULT hr, TResult value) for operations that produce value types. + ~~~ + run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void + { -}); -~~~ -for an agile callback use Microsoft::WRL::FtmBase -~~~ -run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void -{ + }); + ~~~ + for an agile callback use Microsoft::WRL::FtmBase + ~~~ + run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void + { -}); -~~~ -Using the non throwing form: -~~~ -hr = run_when_complete_nothrow(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> HRESULT -{ + }); + ~~~ + Using the non throwing form: + ~~~ + hr = run_when_complete_nothrow(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> HRESULT + { -}); -~~~ -*/ + }); + ~~~ + */ -//! Run a function when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler -//! agile and run on the async thread. -template -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenCompleteAction(operation, wistd::forward(func)); -} + //! Run a function when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the + //! completion handler agile and run on the async thread. + template + HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncAction *operation, TFunc &&func) WI_NOEXCEPT + { + return details::RunWhenCompleteAction(operation, wistd::forward(func)); + } -template ::type> -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenComplete(operation, wistd::forward(func)); -} + template ::type> + HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation *operation, + TFunc &&func) WI_NOEXCEPT + { + return details::RunWhenComplete(operation, wistd::forward(func)); + } -template ::type> -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenComplete(operation, wistd::forward(func)); -} + template ::type> + HRESULT run_when_complete_nothrow( + _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress *operation, + TFunc &&func) WI_NOEXCEPT + { + return details::RunWhenComplete(operation, wistd::forward(func)); + } -template -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenCompleteAction(operation, wistd::forward(func)); -} + template + HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress *operation, + TFunc &&func) WI_NOEXCEPT + { + return details::RunWhenCompleteAction(operation, wistd::forward(func)); + } #ifdef WIL_ENABLE_EXCEPTIONS -//! Run a function when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler -//! agile and run on the async thread. -template -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); -} + //! Run a function when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the + //! completion handler agile and run on the async thread. + template + void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncAction *operation, TFunc &&func) + { + THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); + } -template ::type> -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); -} + template ::type> + void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperation *operation, TFunc &&func) + { + THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); + } -template ::type> -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); -} + template ::type> + void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress *operation, + TFunc &&func) + { + THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); + } -template -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); -} + template + void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress *operation, TFunc &&func) + { + THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); + } #endif #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -/** Wait for an asynchronous operation to complete (or be canceled). -Use to synchronously wait on async operations on background threads. -Do not call from UI threads or STA threads as reentrancy will result. -~~~ -ComPtr> op; -THROW_IF_FAILED(storageFileStatics->GetFileFromPathAsync(HStringReference(path).Get(), &op)); -auto file = wil::wait_for_completion(op.Get()); -~~~ -*/ -template -inline HRESULT wait_for_completion_nothrow(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, flags, INFINITE, nullptr); -} + /** Wait for an asynchronous operation to complete (or be canceled). + Use to synchronously wait on async operations on background threads. + Do not call from UI threads or STA threads as reentrancy will result. + ~~~ + ComPtr> op; + THROW_IF_FAILED(storageFileStatics->GetFileFromPathAsync(HStringReference(path).Get(), &op)); + auto file = wil::wait_for_completion(op.Get()); + ~~~ + */ + template + inline HRESULT wait_for_completion_nothrow(_In_ TAsync *operation, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, flags, INFINITE, nullptr); + } -// These forms return the result from the async operation + // These forms return the result from the async operation -template -HRESULT wait_for_completion_nothrow( - _In_ ABI::Windows::Foundation::IAsyncOperation* operation, - _Out_ typename wil::details::MapAsyncOpResultType::type* result, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); -} + template + HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation *operation, + _Out_ typename wil::details::MapAsyncOpResultType::type *result, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); + } -template -HRESULT wait_for_completion_nothrow( - _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, - _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); -} + template + HRESULT wait_for_completion_nothrow( + _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress *operation, + _Out_ typename wil::details::MapAsyncOpProgressResultType::type *result, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); + } -// Same as above, but allows caller to specify a timeout value. -// On timeout, S_OK is returned, with timedOut set to true. + // Same as above, but allows caller to specify a timeout value. + // On timeout, S_OK is returned, with timedOut set to true. -template -inline HRESULT wait_for_completion_or_timeout_nothrow( - _In_ TAsync* operation, DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, flags, timeoutValue, timedOut); -} + template + inline HRESULT wait_for_completion_or_timeout_nothrow(_In_ TAsync *operation, DWORD timeoutValue, + _Out_ bool *timedOut, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, flags, timeoutValue, timedOut); + } -template -HRESULT wait_for_completion_or_timeout_nothrow( - _In_ ABI::Windows::Foundation::IAsyncOperation* operation, - _Out_ typename wil::details::MapAsyncOpResultType::type* result, - DWORD timeoutValue, - _Out_ bool* timedOut, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); -} + template + HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation *operation, + _Out_ + typename wil::details::MapAsyncOpResultType::type *result, + DWORD timeoutValue, _Out_ bool *timedOut, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); + } -template -HRESULT wait_for_completion_or_timeout_nothrow( - _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, - _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, - DWORD timeoutValue, - _Out_ bool* timedOut, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); -} + template + HRESULT wait_for_completion_or_timeout_nothrow( + _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress *operation, + _Out_ typename wil::details::MapAsyncOpProgressResultType::type *result, DWORD timeoutValue, + _Out_ bool *timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT + { + return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); + } #ifdef WIL_ENABLE_EXCEPTIONS -//! Wait for an asynchronous operation to complete (or be canceled). -template -inline void wait_for_completion(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - THROW_IF_FAILED(details::WaitForCompletion(operation, flags, INFINITE, nullptr)); -} + //! Wait for an asynchronous operation to complete (or be canceled). + template + inline void wait_for_completion(_In_ TAsync *operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) + { + THROW_IF_FAILED(details::WaitForCompletion(operation, flags, INFINITE, nullptr)); + } -template ::type>::type> -TReturn wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - TReturn result; - THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); - return result; -} + template ::type>::type> + TReturn wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation *operation, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) + { + TReturn result; + THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); + return result; + } -template < - typename TResult, - typename TProgress, - typename TReturn = typename wil::details::MapToSmartType::type>::type> -TReturn wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - TReturn result; - THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); - return result; -} + template ::type>::type> + TReturn wait_for_completion( + _In_ ABI::Windows::Foundation::IAsyncOperationWithProgress *operation, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) + { + TReturn result; + THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); + return result; + } -/** Similar to WaitForCompletion but this function encapsulates the creation of the async operation -making usage simpler. -~~~ -ComPtr launcher; // inited somewhere -auto result = call_and_wait_for_completion(launcher.Get(), &ILauncherStatics::LaunchUriAsync, uri.Get()); -~~~ -*/ -template -auto call_and_wait_for_completion(I* object, HRESULT (STDMETHODCALLTYPE I::*func)(P...), Args&&... args) -{ - Microsoft::WRL::ComPtr::type>::type>::type> op; - THROW_IF_FAILED((object->*func)(wistd::forward(args)..., &op)); - return wil::wait_for_completion(op.Get()); -} + /** Similar to WaitForCompletion but this function encapsulates the creation of the async operation + making usage simpler. + ~~~ + ComPtr launcher; // inited somewhere + auto result = call_and_wait_for_completion(launcher.Get(), &ILauncherStatics::LaunchUriAsync, uri.Get()); + ~~~ + */ + template + auto call_and_wait_for_completion(I *object, HRESULT (STDMETHODCALLTYPE I::*func)(P...), Args &&...args) + { + Microsoft::WRL::ComPtr::type>::type>::type> + op; + THROW_IF_FAILED((object->*func)(wistd::forward(args)..., &op)); + return wil::wait_for_completion(op.Get()); + } #endif #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) @@ -1852,184 +1883,194 @@ auto call_and_wait_for_completion(I* object, HRESULT (STDMETHODCALLTYPE I::*func #pragma region WinRT object construction #ifdef WIL_ENABLE_EXCEPTIONS -//! Get a WinRT activation factory object, usually using a IXXXStatics interface. -template -com_ptr GetActivationFactory(PCWSTR runtimeClass) -{ - com_ptr result; - THROW_IF_FAILED(RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), IID_PPV_ARGS(&result))); - return result; -} + //! Get a WinRT activation factory object, usually using a IXXXStatics interface. + template com_ptr GetActivationFactory(PCWSTR runtimeClass) + { + com_ptr result; + THROW_IF_FAILED(RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), + IID_PPV_ARGS(&result))); + return result; + } -//! Get a WinRT object. -template -com_ptr ActivateInstance(PCWSTR runtimeClass) -{ - com_ptr result; - THROW_IF_FAILED(RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), &result)); - return result.query(); -} + //! Get a WinRT object. + template com_ptr ActivateInstance(PCWSTR runtimeClass) + { + com_ptr result; + THROW_IF_FAILED(RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), &result)); + return result.query(); + } #endif #pragma endregion #pragma region Async production helpers -/// @cond -namespace details -{ - template - class SyncAsyncOp WrlFinal : public Microsoft::WRL::RuntimeClass< - ABI::Windows::Foundation::IAsyncOperation, - Microsoft::WRL::AsyncBase>> + /// @cond + namespace details { - // typedef typename MapToSmartType::type TSmart; - using RuntimeClassT = typename SyncAsyncOp::RuntimeClassT; - InspectableClass(__super::z_get_rc_name_impl(), TrustLevel::BaseTrust); - - public: - HRESULT RuntimeClassInitialize(const TResult& op) + template + class SyncAsyncOp WrlFinal + : public Microsoft::WRL::RuntimeClass< + ABI::Windows::Foundation::IAsyncOperation, + Microsoft::WRL::AsyncBase>> { - m_result = op; - return S_OK; - } + // typedef typename MapToSmartType::type TSmart; + using RuntimeClassT = typename SyncAsyncOp::RuntimeClassT; + InspectableClass(__super::z_get_rc_name_impl(), TrustLevel::BaseTrust); - IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler* competed) override - { - competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); - return S_OK; - } + public: + HRESULT RuntimeClassInitialize(const TResult &op) + { + m_result = op; + return S_OK; + } - IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler** competed) override - { - *competed = nullptr; - return S_OK; - } + IFACEMETHODIMP put_Completed( + ABI::Windows::Foundation::IAsyncOperationCompletedHandler *competed) override + { + competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); + return S_OK; + } - IFACEMETHODIMP GetResults(TResult* result) override - { - *result = m_result; - return S_OK; - } + IFACEMETHODIMP get_Completed( + ABI::Windows::Foundation::IAsyncOperationCompletedHandler **competed) override + { + *competed = nullptr; + return S_OK; + } - HRESULT OnStart() override - { - return S_OK; - } - void OnClose() override - { - } - void OnCancel() override - { - } + IFACEMETHODIMP GetResults(TResult *result) override + { + *result = m_result; + return S_OK; + } - private: - // needs to be MapToSmartType::type to hold non trial types - TResult m_result{}; - }; + HRESULT OnStart() override + { + return S_OK; + } + void OnClose() override + { + } + void OnCancel() override + { + } - extern const __declspec(selectany) wchar_t SyncAsyncActionName[] = L"SyncActionAction"; + private: + // needs to be MapToSmartType::type to hold non trial types + TResult m_result{}; + }; - class SyncAsyncActionOp WrlFinal : public Microsoft::WRL::RuntimeClass< - ABI::Windows::Foundation::IAsyncAction, - Microsoft::WRL::AsyncBase< - ABI::Windows::Foundation::IAsyncActionCompletedHandler, - Microsoft::WRL::Details::Nil, - Microsoft::WRL::AsyncResultType::SingleResult + extern const __declspec(selectany) wchar_t SyncAsyncActionName[] = L"SyncActionAction"; + + class SyncAsyncActionOp WrlFinal + : public Microsoft::WRL::RuntimeClass< + ABI::Windows::Foundation::IAsyncAction, + Microsoft::WRL::AsyncBase + , + Microsoft::WRL::AsyncCausalityOptions #endif - >> + >> + { + InspectableClass(InterfaceName_Windows_Foundation_IAsyncAction, TrustLevel::BaseTrust); + + public: + IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler *competed) override + { + competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); + return S_OK; + } + + IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler **competed) override + { + *competed = nullptr; + return S_OK; + } + + IFACEMETHODIMP GetResults() override + { + return S_OK; + } + + HRESULT OnStart() override + { + return S_OK; + } + void OnClose() override + { + } + void OnCancel() override + { + } + }; + } // namespace details + /// @endcond + + //! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for + //! mocking APIs. + template + HRESULT make_synchronous_async_operation_nothrow(ABI::Windows::Foundation::IAsyncOperation **result, + const TResult &value) { - InspectableClass(InterfaceName_Windows_Foundation_IAsyncAction, TrustLevel::BaseTrust); + return Microsoft::WRL::MakeAndInitialize>(result, value); + } - public: - IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler* competed) override - { - competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); - return S_OK; - } - - IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler** competed) override - { - *competed = nullptr; - return S_OK; - } - - IFACEMETHODIMP GetResults() override - { - return S_OK; - } - - HRESULT OnStart() override - { - return S_OK; - } - void OnClose() override - { - } - void OnCancel() override - { - } - }; -} // namespace details -/// @endcond - -//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. -template -HRESULT make_synchronous_async_operation_nothrow(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) -{ - return Microsoft::WRL::MakeAndInitialize>(result, value); -} - -//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. -inline HRESULT make_synchronous_async_action_nothrow(ABI::Windows::Foundation::IAsyncAction** result) -{ - return Microsoft::WRL::MakeAndInitialize(result); -} + //! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking + //! APIs. + inline HRESULT make_synchronous_async_action_nothrow(ABI::Windows::Foundation::IAsyncAction **result) + { + return Microsoft::WRL::MakeAndInitialize(result); + } #ifdef WIL_ENABLE_EXCEPTIONS -//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. -// TODO: map TRealResult and TSmartResult into SyncAsyncOp. -template ::type, typename TSmartResult = typename details::MapToSmartType::type> -void make_synchronous_async_operation(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) -{ - THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize>(result, value))); -} + //! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for + //! mocking APIs. + // TODO: map TRealResult and TSmartResult into SyncAsyncOp. + template ::type, + typename TSmartResult = typename details::MapToSmartType::type> + void make_synchronous_async_operation(ABI::Windows::Foundation::IAsyncOperation **result, + const TResult &value) + { + THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize>(result, value))); + } -//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. -inline void make_synchronous_async_action(ABI::Windows::Foundation::IAsyncAction** result) -{ - THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize(result))); -} + //! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking + //! APIs. + inline void make_synchronous_async_action(ABI::Windows::Foundation::IAsyncAction **result) + { + THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize(result))); + } #endif #pragma endregion #pragma region EventRegistrationToken RAII wrapper -// unique_winrt_event_token[_cx] is an RAII wrapper around EventRegistrationToken. When the unique_winrt_event_token[_cx] is -// destroyed, the event is automatically unregistered. Declare a wil::unique_winrt_event_token[_cx] at the scope the event -// should be registered for (often they are tied to object lifetime), where T is the type of the event sender -// wil::unique_winrt_event_token_cx m_token; -// -// Macros have been defined to register for handling the event and then returning an unique_winrt_event_token[_cx]. These -// macros simply hide the function references for adding and removing the event. -// C++/CX m_token = WI_MakeUniqueWinRtEventTokenCx(ExampleEventName, sender, handler); -// ABI m_token = WI_MakeUniqueWinRtEventToken(ExampleEventName, sender, handler, &m_token); // Exception and failfast -// ABI RETURN_IF_FAILED(WI_MakeUniqueWinRtEventTokenNoThrow(ExampleEventName, sender, handler, &m_token)); // No throw variant -// -// When the wrapper is destroyed, the handler will be unregistered. You can explicitly unregister the handler prior. -// m_token.reset(); -// -// You can release the EventRegistrationToken from being managed by the wrapper by calling .release() -// m_token.release(); // DANGER: no longer being managed -// -// If you just need the value of the EventRegistrationToken you can call .get() -// m_token.get(); -// -// See "onecore\shell\tests\wil\UniqueWinRTEventTokenTests.cpp" for more examples of usage in ABI and C++/CX. + // unique_winrt_event_token[_cx] is an RAII wrapper around EventRegistrationToken. When the + // unique_winrt_event_token[_cx] is destroyed, the event is automatically unregistered. Declare a + // wil::unique_winrt_event_token[_cx] at the scope the event should be registered for (often they are tied to + // object lifetime), where T is the type of the event sender + // wil::unique_winrt_event_token_cx m_token; + // + // Macros have been defined to register for handling the event and then returning an unique_winrt_event_token[_cx]. + // These macros simply hide the function references for adding and removing the event. + // C++/CX m_token = WI_MakeUniqueWinRtEventTokenCx(ExampleEventName, sender, handler); + // ABI m_token = WI_MakeUniqueWinRtEventToken(ExampleEventName, sender, handler, &m_token); // Exception and + // failfast ABI RETURN_IF_FAILED(WI_MakeUniqueWinRtEventTokenNoThrow(ExampleEventName, sender, handler, + // &m_token)); // No throw variant + // + // When the wrapper is destroyed, the handler will be unregistered. You can explicitly unregister the handler prior. + // m_token.reset(); + // + // You can release the EventRegistrationToken from being managed by the wrapper by calling .release() + // m_token.release(); // DANGER: no longer being managed + // + // If you just need the value of the EventRegistrationToken you can call .get() + // m_token.get(); + // + // See "onecore\shell\tests\wil\UniqueWinRTEventTokenTests.cpp" for more examples of usage in ABI and C++/CX. -// clang-format off + // clang-format off #ifdef __cplusplus_winrt namespace details { @@ -2162,97 +2203,97 @@ private: }; #endif -// clang-format on + // clang-format on -template -class unique_winrt_event_token -{ - using removal_func = HRESULT (__stdcall T::*)(::EventRegistrationToken); - -public: - unique_winrt_event_token() = default; - - unique_winrt_event_token(::EventRegistrationToken token, T* sender, removal_func removalFunction) WI_NOEXCEPT - : m_token(token), - m_removalFunction(removalFunction) + template class unique_winrt_event_token { - m_weakSender = wil::com_weak_query_failfast(sender); - } + using removal_func = HRESULT (__stdcall T::*)(::EventRegistrationToken); - unique_winrt_event_token(const unique_winrt_event_token&) = delete; - unique_winrt_event_token& operator=(const unique_winrt_event_token&) = delete; + public: + unique_winrt_event_token() = default; - unique_winrt_event_token(unique_winrt_event_token&& other) WI_NOEXCEPT : m_token(other.m_token), - m_weakSender(wistd::move(other.m_weakSender)), - m_removalFunction(other.m_removalFunction) - { - other.m_token = {}; - other.m_removalFunction = nullptr; - } + unique_winrt_event_token(::EventRegistrationToken token, T *sender, removal_func removalFunction) WI_NOEXCEPT + : m_token(token), + m_removalFunction(removalFunction) + { + m_weakSender = wil::com_weak_query_failfast(sender); + } - unique_winrt_event_token& operator=(unique_winrt_event_token&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) + unique_winrt_event_token(const unique_winrt_event_token &) = delete; + unique_winrt_event_token &operator=(const unique_winrt_event_token &) = delete; + + unique_winrt_event_token(unique_winrt_event_token &&other) WI_NOEXCEPT + : m_token(other.m_token), + m_weakSender(wistd::move(other.m_weakSender)), + m_removalFunction(other.m_removalFunction) + { + other.m_token = {}; + other.m_removalFunction = nullptr; + } + + unique_winrt_event_token &operator=(unique_winrt_event_token &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + + wistd::swap_wil(m_token, other.m_token); + wistd::swap_wil(m_weakSender, other.m_weakSender); + wistd::swap_wil(m_removalFunction, other.m_removalFunction); + } + + return *this; + } + + ~unique_winrt_event_token() WI_NOEXCEPT { reset(); - - wistd::swap_wil(m_token, other.m_token); - wistd::swap_wil(m_weakSender, other.m_weakSender); - wistd::swap_wil(m_removalFunction, other.m_removalFunction); } - return *this; - } - - ~unique_winrt_event_token() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_token.value != 0); - } - - WI_NODISCARD ::EventRegistrationToken get() const WI_NOEXCEPT - { - return m_token; - } - - void reset() WI_NOEXCEPT - { - if (m_token.value != 0) + WI_NODISCARD explicit operator bool() const WI_NOEXCEPT { - // If T cannot be QI'ed from the weak object then T is not a COM interface. - auto resolvedSender = m_weakSender.try_query(); - if (resolvedSender) - { - FAIL_FAST_IF_FAILED((resolvedSender.get()->*m_removalFunction)(m_token)); - } - release(); + return (m_token.value != 0); } - } - // Stops the wrapper from managing resource and returns the EventRegistrationToken. - ::EventRegistrationToken release() WI_NOEXCEPT + WI_NODISCARD ::EventRegistrationToken get() const WI_NOEXCEPT + { + return m_token; + } + + void reset() WI_NOEXCEPT + { + if (m_token.value != 0) + { + // If T cannot be QI'ed from the weak object then T is not a COM interface. + auto resolvedSender = m_weakSender.try_query(); + if (resolvedSender) + { + FAIL_FAST_IF_FAILED((resolvedSender.get()->*m_removalFunction)(m_token)); + } + release(); + } + } + + // Stops the wrapper from managing resource and returns the EventRegistrationToken. + ::EventRegistrationToken release() WI_NOEXCEPT + { + auto token = m_token; + m_token = {}; + m_weakSender = nullptr; + m_removalFunction = nullptr; + return token; + } + + private: + ::EventRegistrationToken m_token = {}; + wil::com_weak_ref_failfast m_weakSender; + removal_func m_removalFunction = nullptr; + }; + + /// @cond + namespace details { - auto token = m_token; - m_token = {}; - m_weakSender = nullptr; - m_removalFunction = nullptr; - return token; - } - -private: - ::EventRegistrationToken m_token = {}; - wil::com_weak_ref_failfast m_weakSender; - removal_func m_removalFunction = nullptr; -}; - -/// @cond -namespace details -{ - // clang-format off + // clang-format off #ifdef __cplusplus_winrt // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. @@ -2276,74 +2317,69 @@ namespace details } #endif // __cplusplus_winrt - // clang-format on + // clang-format on - // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. - // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventToken macro to abstract away specifying the functions that handle addition and removal. - template - inline auto make_unique_winrt_event_token( - T* sender, addition_func additionFunc, removal_func removalFunc, handler h, wil::unique_winrt_event_token* token_reference) - { - ::EventRegistrationToken rawToken; - err_policy::HResult((sender->*additionFunc)(h, &rawToken)); - *token_reference = wil::unique_winrt_event_token(rawToken, sender, removalFunc); - return err_policy::OK(); - } + // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken + // in unique_winrt_event_token. Not intended to be directly called. Use the WI_MakeUniqueWinRtEventToken macro + // to abstract away specifying the functions that handle addition and removal. + template + inline auto make_unique_winrt_event_token(T *sender, addition_func additionFunc, removal_func removalFunc, + handler h, wil::unique_winrt_event_token *token_reference) + { + ::EventRegistrationToken rawToken; + err_policy::HResult((sender->*additionFunc)(h, &rawToken)); + *token_reference = wil::unique_winrt_event_token(rawToken, sender, removalFunc); + return err_policy::OK(); + } - // Overload make function to allow for returning the constructed object when not using HRESULT based code. - template - inline typename wistd::enable_if::value, wil::unique_winrt_event_token>::type make_unique_winrt_event_token( - T* sender, addition_func additionFunc, removal_func removalFunc, handler h) - { - ::EventRegistrationToken rawToken; - err_policy::HResult((sender->*additionFunc)(h, &rawToken)); - return wil::unique_winrt_event_token(rawToken, sender, removalFunc); - } + // Overload make function to allow for returning the constructed object when not using HRESULT based code. + template + inline typename wistd::enable_if::value, + wil::unique_winrt_event_token>::type + make_unique_winrt_event_token(T *sender, addition_func additionFunc, removal_func removalFunc, handler h) + { + ::EventRegistrationToken rawToken; + err_policy::HResult((sender->*additionFunc)(h, &rawToken)); + return wil::unique_winrt_event_token(rawToken, sender, removalFunc); + } -} // namespace details + } // namespace details /// @endcond // Helper macros to abstract function names for event addition and removal. #ifdef __cplusplus_winrt -#define WI_MakeUniqueWinRtEventTokenCx(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token_cx( \ - _object, \ - &wil::details::remove_reference::type::##_event## ::add, \ - &wil::details::remove_reference::type::##_event## ::remove, \ - _handler) +#define WI_MakeUniqueWinRtEventTokenCx(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token_cx( \ + _object, &wil::details::remove_reference::type::##_event## ::add, \ + &wil::details::remove_reference::type::##_event## ::remove, _handler) -#define WI_MakeUniqueWinRtStaticEventTokenCx(_event, _baseType, _handler) \ - wil::details::make_unique_winrt_static_event_token_cx<_baseType>( \ - &##_baseType## ::##_event## ::add, &##_baseType## ::##_event## ::remove, _handler) +#define WI_MakeUniqueWinRtStaticEventTokenCx(_event, _baseType, _handler) \ + wil::details::make_unique_winrt_static_event_token_cx<_baseType>(&##_baseType## ::##_event## ::add, \ + &##_baseType## ::##_event## ::remove, _handler) #endif // __cplusplus_winrt #ifdef WIL_ENABLE_EXCEPTIONS -#define WI_MakeUniqueWinRtEventToken(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler) +#define WI_MakeUniqueWinRtEventToken(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token( \ + _object, &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, _handler) #endif // WIL_ENABLE_EXCEPTIONS -#define WI_MakeUniqueWinRtEventTokenNoThrow(_event, _object, _handler, _token_reference) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler, \ - _token_reference) +#define WI_MakeUniqueWinRtEventTokenNoThrow(_event, _object, _handler, _token_reference) \ + wil::details::make_unique_winrt_event_token( \ + _object, &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, _handler, _token_reference) -#define WI_MakeUniqueWinRtEventTokenFailFast(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler) +#define WI_MakeUniqueWinRtEventTokenFailFast(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token( \ + _object, &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, _handler) #pragma endregion // EventRegistrationToken RAII wrapper @@ -2352,120 +2388,130 @@ namespace details #if (NTDDI_VERSION >= NTDDI_WINBLUE) /// @cond template <> -struct ABI::Windows::Foundation::IAsyncOperation - : ABI::Windows::Foundation::IAsyncOperation_impl +struct ABI::Windows::Foundation::IAsyncOperation + : ABI::Windows::Foundation::IAsyncOperation_impl { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperation"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress - : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl +struct ABI::Windows::Foundation::IAsyncOperationWithProgress + : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgress"; } }; template -struct ABI::Windows::Foundation::IAsyncOperation*> - : ABI::Windows::Foundation::IAsyncOperation_impl*> +struct ABI::Windows::Foundation::IAsyncOperation *> + : ABI::Windows::Foundation::IAsyncOperation_impl *> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperation*>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, P> - : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, P> +struct ABI::Windows::Foundation::IAsyncOperationWithProgress *, P> + : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl *, P> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgress*,P>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperation*> - : ABI::Windows::Foundation::IAsyncOperation_impl*> +struct ABI::Windows::Foundation::IAsyncOperation *> + : ABI::Windows::Foundation::IAsyncOperation_impl *> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperation*>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, Z> - : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, Z> +struct ABI::Windows::Foundation::IAsyncOperationWithProgress< + ABI::Windows::Foundation::IAsyncOperationWithProgress *, Z> + : ABI::Windows::Foundation::IAsyncOperationWithProgress_impl< + ABI::Windows::Foundation::IAsyncOperationWithProgress *, Z> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgress*,Z>"; } }; template <> -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler - : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler + : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler - : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler + : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl< + ABI::Windows::Foundation::IAsyncAction *, P> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> - : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler *> + : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl *> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler*>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, P> - : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, P> +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler< + ABI::Windows::Foundation::IAsyncOperation *, P> + : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl< + ABI::Windows::Foundation::IAsyncOperation *, P> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler*,P>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> - : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler< + ABI::Windows::Foundation::IAsyncOperationWithProgress *> + : ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl< + ABI::Windows::Foundation::IAsyncOperationWithProgress *> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationCompletedHandler*>"; } }; template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, Z> - : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, Z> +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler< + ABI::Windows::Foundation::IAsyncOperationWithProgress *, Z> + : ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl< + ABI::Windows::Foundation::IAsyncOperationWithProgress *, Z> { - static const wchar_t* z_get_rc_name_impl() + static const wchar_t *z_get_rc_name_impl() { return L"IAsyncOperationWithProgressCompletedHandler*,Z>"; } @@ -2482,19 +2528,17 @@ struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler -struct less : public wil::hstring_less -{ -}; + //! Specialization of `std::less` for `Microsoft::WRL::Wrappers::HString` that uses `hstring_less` for the + //! comparison function object. + template <> struct less : public wil::hstring_less + { + }; -//! Specialization of `std::less` for `wil::unique_hstring` that uses `hstring_less` for the comparison function -//! object. -template <> -struct less : public wil::hstring_less -{ -}; + //! Specialization of `std::less` for `wil::unique_hstring` that uses `hstring_less` for the comparison function + //! object. + template <> struct less : public wil::hstring_less + { + }; } // namespace std #endif diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_config.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_config.h index 2efb981..c4e757e 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_config.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_config.h @@ -171,7 +171,7 @@ #define __WI_ALIGNAS(x) __attribute__((__aligned__(x))) #endif -#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \ +#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 @@ -411,7 +411,8 @@ #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)) +#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 @@ -473,113 +474,113 @@ namespace wistd // ("Windows Implementation" std) { -using nullptr_t = decltype(__nullptr); + using nullptr_t = decltype(__nullptr); -template -struct __less -{ - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()( - const _T1& __x, const _T1& __y) const + template struct __less { - return __x < __y; + __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 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 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; + } + }; + + template 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 + 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; } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()( - const _T1& __x, const _T2& __y) const + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp &(min)(const _Tp &__a, + const _Tp &__b) { - return __x < __y; + return (min)(__a, __b, __less<_Tp>()); } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()( - const _T2& __x, const _T1& __y) const + // max + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp &(max)(const _Tp &__a, + const _Tp &__b, + _Compare __comp) { - return __x < __y; + return __comp(__a, __b) ? __b : __a; } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()( - const _T2& __x, const _T2& __y) const + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp &(max)(const _Tp &__a, + const _Tp &__b) { - return __x < __y; + return (max)(__a, __b, __less<_Tp>()); } -}; -template -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 + template struct __WI_LIBCPP_TEMPLATE_VIS unary_function { - return __x < __y; - } -}; + using argument_type = _Arg; + using result_type = _Result; + }; -template -struct __less -{ - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()( - const _T1& __x, const _T1& __y) const + template struct __WI_LIBCPP_TEMPLATE_VIS binary_function { - return __x < __y; - } -}; - -template -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 -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 -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 -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 -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 -struct __WI_LIBCPP_TEMPLATE_VIS unary_function -{ - using argument_type = _Arg; - using result_type = _Result; -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS binary_function -{ - using first_argument_type = _Arg1; - using second_argument_type = _Arg2; - using result_type = _Result; -}; + using first_argument_type = _Arg1; + using second_argument_type = _Arg2; + using result_type = _Result; + }; } // namespace wistd /// @endcond diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_functional.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_functional.h index 73bc4e6..f6e1311 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_functional.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_functional.h @@ -51,509 +51,483 @@ /// @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) + // 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 -struct __invoke_void_return_wrapper -{ -#ifndef __WI_LIBCPP_CXX03_LANG - template - static _Ret __call(_Args&&... __args) + template struct __invoke_void_return_wrapper { - return __invoke(wistd::forward<_Args>(__args)...); - } +#ifndef __WI_LIBCPP_CXX03_LANG + template static _Ret __call(_Args &&...__args) + { + return __invoke(wistd::forward<_Args>(__args)...); + } #else - template - static _Ret __call(_Fn __f) - { - return __invoke(__f); - } + template static _Ret __call(_Fn __f) + { + return __invoke(__f); + } - template - static _Ret __call(_Fn __f, _A0& __a0) - { - return __invoke(__f, __a0); - } + template static _Ret __call(_Fn __f, _A0 &__a0) + { + return __invoke(__f, __a0); + } - template - static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1) - { - return __invoke(__f, __a0, __a1); - } + template static _Ret __call(_Fn __f, _A0 &__a0, _A1 &__a1) + { + return __invoke(__f, __a0, __a1); + } - template - static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) - { - return __invoke(__f, __a0, __a1, __a2); - } + template + static _Ret __call(_Fn __f, _A0 &__a0, _A1 &__a1, _A2 &__a2) + { + return __invoke(__f, __a0, __a1, __a2); + } #endif -}; + }; -template <> -struct __invoke_void_return_wrapper -{ -#ifndef __WI_LIBCPP_CXX03_LANG - template - static void __call(_Args&&... __args) + template <> struct __invoke_void_return_wrapper { - (void)__invoke(wistd::forward<_Args>(__args)...); - } +#ifndef __WI_LIBCPP_CXX03_LANG + template static void __call(_Args &&...__args) + { + (void)__invoke(wistd::forward<_Args>(__args)...); + } #else - template - static void __call(_Fn __f) - { - __invoke(__f); - } + template static void __call(_Fn __f) + { + __invoke(__f); + } - template - static void __call(_Fn __f, _A0& __a0) - { - __invoke(__f, __a0); - } + template static void __call(_Fn __f, _A0 &__a0) + { + __invoke(__f, __a0); + } - template - static void __call(_Fn __f, _A0& __a0, _A1& __a1) - { - __invoke(__f, __a0, __a1); - } + template static void __call(_Fn __f, _A0 &__a0, _A1 &__a1) + { + __invoke(__f, __a0, __a1); + } - template - static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) - { - __invoke(__f, __a0, __a1, __a2); - } + template + 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 __WI_LIBCPP_TEMPLATE_VIS function; // undefined - -namespace __function -{ - - template - struct __maybe_derive_from_unary_function - { }; - template - struct __maybe_derive_from_unary_function<_Rp(_A1)> : public unary_function<_A1, _Rp> - { - }; + //////////////////////////////////////////////////////////////////////////////// + // FUNCTION + //============================================================================== - template - struct __maybe_derive_from_binary_function - { - }; + // bad_function_call - template - struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public binary_function<_A1, _A2, _Rp> + __WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY void __throw_bad_function_call() { - }; - - template - __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp const&) - { - return true; + __fastfail(7); // FAST_FAIL_FATAL_APP_EXIT } - template - __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp* __ptr) - { - return __ptr; - } + template class __WI_LIBCPP_TEMPLATE_VIS function; // undefined - template - __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Ret _Class::* __ptr) + namespace __function { - return __ptr; - } - template - __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(function<_Fp> const& __f) - { - return !!__f; - } + template struct __maybe_derive_from_unary_function + { + }; -} // namespace __function + template + struct __maybe_derive_from_unary_function<_Rp(_A1)> : public unary_function<_A1, _Rp> + { + }; + + template struct __maybe_derive_from_binary_function + { + }; + + template + struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public binary_function<_A1, _A2, _Rp> + { + }; + + template __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp const &) + { + return true; + } + + template __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp *__ptr) + { + return __ptr; + } + + template __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Ret _Class::*__ptr) + { + return __ptr; + } + + template __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(function<_Fp> const &__f) + { + return !!__f; + } + + } // namespace __function #ifndef __WI_LIBCPP_CXX03_LANG -namespace __function -{ + namespace __function + { - template - class __base; + template class __base; + + template 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 __func; + + template + 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 + void __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)> *__p) const + { + ::new (__p) __func(__f_); + } + + template + void __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)> *__p) + { + ::new (__p) __func(wistd::move(__f_)); + } + + template void __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT + { + __f_.~_Fp(); + } + + template + _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 __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 struct __callable_imp + { + static const bool value = is_same::value || + is_convertible::type, _Rp>::value; + }; + + template struct __callable_imp<_Fp, false> + { + static constexpr bool value = false; + }; + + template struct __callable + { + static const bool value = + __callable_imp<_Fp, __lazy_and, function>::value>, + __invokable<_Fp &, _ArgTypes...>>::value>::value; + }; + + template 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 > function(_Fp); + + function &operator=(const function &); + function &operator=(function &&); + function &operator=(nullptr_t) WI_NOEXCEPT; + template > 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 bool operator==(const function<_R2(_ArgTypes2...)> &) const = delete; + template 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 __base<_Rp(_ArgTypes...)> + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(const function &__f) { - __base(const __base&); - __base& operator=(const __base&); - - public: - __WI_LIBCPP_INLINE_VISIBILITY __base() + if (__f.__f_ == nullptr) + __f_ = 0; + else { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); } - __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 __func; - - template - class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> + template + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS + function<_Rp(_ArgTypes...)>::function(function &&__f) { - _Fp __f_; - - public: - __WI_LIBCPP_INLINE_VISIBILITY - explicit __func(_Fp&& __f) : __f_(wistd::move(__f)) + if (__f.__f_ == nullptr) + __f_ = 0; + else { + __f_ = __as_base(&__buf_); + __f.__f_->__move(__f_); + __f.__f_->destroy(); + __f.__f_ = 0; + } + } + + template + template + __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(&__buf_)) _FF(wistd::move(__f)); + } + } + + template + 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 + 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 + function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT + { + __base *__t = __f_; + __f_ = 0; + if (__t) + __t->destroy(); + return *this; + } + + template + template + function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(_Fp &&__f) + { + *this = nullptr; + if (__function::__not_null(__f)) + { + typedef __function::__func::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(&__buf_)) _FF(wistd::move(__f)); } - __WI_LIBCPP_INLINE_VISIBILITY - explicit __func(const _Fp& __f) : __f_(__f) + return *this; + } + + template function<_Rp(_ArgTypes...)>::~function() + { + if (__f_) + __f_->destroy(); + } + + template void function<_Rp(_ArgTypes...)>::swap(function &__f) + { + if (wistd::addressof(__f) == this) + return; + if (__f_ && __f.__f_) { + typename aligned_storage::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_); } - - virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; - virtual void __move(__base<_Rp(_ArgTypes...)>*); - virtual void destroy() WI_NOEXCEPT; - virtual _Rp operator()(_ArgTypes&&... __arg); - }; - - template - void __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const - { - ::new (__p) __func(__f_); } - template - void __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p) + template _Rp function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const { - ::new (__p) __func(wistd::move(__f_)); + if (__f_ == nullptr) + __throw_bad_function_call(); + return (*__f_)(wistd::forward<_ArgTypes>(__arg)...); } - template - void __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const function<_Rp(_ArgTypes...)> &__f, nullptr_t) WI_NOEXCEPT { - __f_.~_Fp(); + return !__f; } - template - _Rp __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const function<_Rp(_ArgTypes...)> &__f) WI_NOEXCEPT { - typedef __invoke_void_return_wrapper<_Rp> _Invoker; - return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...); + return !__f; } - // '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 __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) + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const function<_Rp(_ArgTypes...)> &__f, nullptr_t) WI_NOEXCEPT { - return static_cast<__base*>(p); + return (bool)__f; } - template - struct __callable_imp - { - static const bool value = is_same::value || is_convertible::type, _Rp>::value; - }; - - template - struct __callable_imp<_Fp, false> - { - static constexpr bool value = false; - }; - - template - struct __callable - { - static const bool value = - __callable_imp<_Fp, __lazy_and, function>::value>, __invokable<_Fp&, _ArgTypes...>>::value>::value; - }; - - template - 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) + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const function<_Rp(_ArgTypes...)> &__f) WI_NOEXCEPT { + return (bool)__f; } - __WI_LIBCPP_INLINE_VISIBILITY - function(nullptr_t) WI_NOEXCEPT : __f_(0) + // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work + template + inline __WI_LIBCPP_INLINE_VISIBILITY void swap(function<_Rp(_ArgTypes...)> &__x, function<_Rp(_ArgTypes...)> &__y) { - } - function(const function&); - function(function&&); - template > - function(_Fp); - - function& operator=(const function&); - function& operator=(function&&); - function& operator=(nullptr_t) WI_NOEXCEPT; - template > - 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_; + return __x.swap(__y); } - // deleted overloads close possible hole in the type system - template - bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete; - template - 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 -__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(const function& __f) -{ - if (__f.__f_ == nullptr) - __f_ = 0; - else + template + inline __WI_LIBCPP_INLINE_VISIBILITY void swap_wil(function<_Rp(_ArgTypes...)> &__x, + function<_Rp(_ArgTypes...)> &__y) { - __f_ = __as_base(&__buf_); - __f.__f_->__clone(__f_); - } -} - -template -__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 -template -__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(&__buf_)) _FF(wistd::move(__f)); - } -} - -template -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 -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 -function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT -{ - __base* __t = __f_; - __f_ = 0; - if (__t) - __t->destroy(); - return *this; -} - -template -template -function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f) -{ - *this = nullptr; - if (__function::__not_null(__f)) - { - typedef __function::__func::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(&__buf_)) _FF(wistd::move(__f)); + return __x.swap(__y); } - return *this; -} - -template -function<_Rp(_ArgTypes...)>::~function() -{ - if (__f_) - __f_->destroy(); -} - -template -void function<_Rp(_ArgTypes...)>::swap(function& __f) -{ - if (wistd::addressof(__f) == this) - return; - if (__f_ && __f.__f_) + // std::invoke + template + typename __invoke_of<_Fn, _Args...>::type invoke(_Fn &&__f, _Args &&...__args) + __WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value)) { - typename aligned_storage::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_); + return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...); } - 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 -_Rp function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const -{ - if (__f_ == nullptr) - __throw_bad_function_call(); - return (*__f_)(wistd::forward<_ArgTypes>(__arg)...); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT -{ - return !__f; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT -{ - return !__f; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT -{ - return (bool)__f; -} - -template -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 -inline __WI_LIBCPP_INLINE_VISIBILITY void swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) -{ - return __x.swap(__y); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY void swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) -{ - return __x.swap(__y); -} - -// std::invoke -template -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 diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_memory.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_memory.h index 61e14c7..3443a30 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_memory.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_memory.h @@ -45,945 +45,973 @@ /// @cond namespace wistd // ("Windows Implementation" std) { -// allocator_traits + // allocator_traits -template -struct __has_pointer_type : false_type -{ -}; - -template -struct __has_pointer_type<_Tp, typename __void_t::type> : true_type -{ -}; - -namespace __pointer_type_imp -{ - - template ::value> - struct __pointer_type - { - using type = typename _Dp::pointer; - }; - - template - struct __pointer_type<_Tp, _Dp, false> - { - using type = _Tp*; - }; - -} // namespace __pointer_type_imp - -template -struct __pointer_type -{ - using type = typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type; -}; - -template ::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 ::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 -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 ::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 __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, _Dummy>::value && __dependent_type, _Dummy>::value>::type> - __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair() - { - } - - template ::type, __compressed_pair>::value, bool>::type = true> - __WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair(_Tp&& __t) : _Base1(wistd::forward<_Tp>(__t)), _Base2() - { - } - - template - __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair(__second_tag, _Tp&& __t) : - _Base1(), _Base2(wistd::forward<_Tp>(__t)) - { - } - - template - __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 -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 -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 -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 - __WI_LIBCPP_INLINE_VISIBILITY default_delete( - const default_delete<_Up>&, typename enable_if::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 -struct __WI_LIBCPP_TEMPLATE_VIS default_delete<_Tp[]> -{ -private: - template - struct _EnableIfConvertible : enable_if::value> + template struct __has_pointer_type : false_type { }; -public: -#ifndef __WI_LIBCPP_CXX03_LANG - __WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default; -#else - __WI_LIBCPP_INLINE_VISIBILITY default_delete() + template struct __has_pointer_type<_Tp, typename __void_t::type> : true_type { - } + }; + + namespace __pointer_type_imp + { + + template ::value> struct __pointer_type + { + using type = typename _Dp::pointer; + }; + + template struct __pointer_type<_Tp, _Dp, false> + { + using type = _Tp *; + }; + + } // namespace __pointer_type_imp + + template struct __pointer_type + { + using type = typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type; + }; + + template ::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 ::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 - template - __WI_LIBCPP_INLINE_VISIBILITY default_delete(const default_delete<_Up[]>&, typename _EnableIfConvertible<_Up>::type* = nullptr) WI_NOEXCEPT - { - } + __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_; + } - template - __WI_LIBCPP_INLINE_VISIBILITY typename _EnableIfConvertible<_Up>::type operator()(_Up* __ptr) const WI_NOEXCEPT + private: + _Tp __value_; + }; + + template struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp { - 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; - } -}; + using _ParamT = _Tp; + using reference = _Tp &; + using const_reference = const _Tp &; + using __value_type = _Tp; #ifndef __WI_LIBCPP_CXX03_LANG -template -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; -}; + __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() = default; -template -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 ::type>::value>::type> + __WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair_elem(_Up &&__u) + : __value_type(wistd::forward<_Up>(__u)) + { + } -template -struct __unique_ptr_deleter_sfinae<_Deleter&> -{ - using __lval_ref_type = _Deleter&; - using __bad_rval_ref_type = _Deleter&&; - using __enable_rval_overload = false_type; -}; + // 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 __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 , _Dummy>::value && + __dependent_type, _Dummy>::value>::type> + __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair() + { + } + + template ::type, __compressed_pair>::value, bool>::type = true> + __WI_LIBCPP_INLINE_VISIBILITY constexpr explicit __compressed_pair(_Tp &&__t) + : _Base1(wistd::forward<_Tp>(__t)), _Base2() + { + } + + template + __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair(__second_tag, _Tp &&__t) + : _Base1(), _Base2(wistd::forward<_Tp>(__t)) + { + } + + template + __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 + 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 + 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 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 + __WI_LIBCPP_INLINE_VISIBILITY default_delete( + const default_delete<_Up> &, + typename enable_if::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 struct __WI_LIBCPP_TEMPLATE_VIS default_delete<_Tp[]> + { + private: + template struct _EnableIfConvertible : enable_if::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 + __WI_LIBCPP_INLINE_VISIBILITY default_delete(const default_delete<_Up[]> &, + typename _EnableIfConvertible<_Up>::type * = nullptr) WI_NOEXCEPT + { + } + + template + __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 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 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 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 __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::value, "the specified deleter type cannot be an rvalue reference"); - -private: - __compressed_pair __ptr_; - - struct __nat + template > class __WI_LIBCPP_TEMPLATE_VIS unique_ptr { - int __for_bool_; - }; + public: + using element_type = _Tp; + using deleter_type = _Dp; + using pointer = typename __pointer_type<_Tp, deleter_type>::type; + + static_assert(!is_rvalue_reference::value, + "the specified deleter type cannot be an rvalue reference"); + + private: + __compressed_pair __ptr_; + + struct __nat + { + int __for_bool_; + }; #ifndef __WI_LIBCPP_CXX03_LANG - using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; + using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; - template - using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; + template using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; - template - using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; + template + using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; - template - using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; + template + using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; - template , _Dummy>::type> - using _EnableIfDeleterDefaultConstructible = - typename enable_if::value && !is_pointer<_Deleter>::value>::type; + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && !is_pointer<_Deleter>::value>::type; - template - using _EnableIfDeleterConstructible = typename enable_if::value>::type; + template + using _EnableIfDeleterConstructible = typename enable_if::value>::type; - template - using _EnableIfMoveConvertible = - typename enable_if::value && !is_array<_Up>::value>::type; + template + using _EnableIfMoveConvertible = + typename enable_if::value && !is_array<_Up>::value>::type; - template - 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 + 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 - using _EnableIfDeleterAssignable = typename enable_if::value>::type; + template + using _EnableIfDeleterAssignable = typename enable_if::value>::type; -public: - template > - __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) - { - } + public: + template > + __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) + { + } - template > - __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) - { - } + template > + __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) + { + } - template > - __WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) WI_NOEXCEPT : __ptr_(__p) - { - } + template > + __WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) WI_NOEXCEPT : __ptr_(__p) + { + } - template >> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d) - { - } + template >> + __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d) + { + } - template >> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, wistd::move(__d)) - { - static_assert(!is_reference::value, "rvalue deleter bound to reference"); - } + template >> + __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(__p, wistd::move(__d)) + { + static_assert(!is_reference::value, "rvalue deleter bound to reference"); + } - template >> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; + template >> + __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(__u.get_deleter())) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr &&__u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) + { + } - template , _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 , _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(__u.get_deleter()); - return *this; - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr &operator=(unique_ptr &&__u) WI_NOEXCEPT + { + reset(__u.release()); + __ptr_.second() = wistd::forward(__u.get_deleter()); + return *this; + } - template , _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; - } + template , _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 - unique_ptr(unique_ptr<_Up, _Ep>&); + private: + unique_ptr(unique_ptr &); + template unique_ptr(unique_ptr<_Up, _Ep> &); - unique_ptr& operator=(unique_ptr&); - template - unique_ptr& operator=(unique_ptr<_Up, _Ep>&); + unique_ptr &operator=(unique_ptr &); + template unique_ptr &operator=(unique_ptr<_Up, _Ep> &); -public: - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr() : __ptr_(pointer()) - { - static_assert(!is_pointer::value, "unique_ptr constructed with null function pointer deleter"); - static_assert(is_default_constructible::value, "unique_ptr::deleter_type is not default constructible"); - } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t) : __ptr_(pointer()) - { - static_assert(!is_pointer::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::value, "unique_ptr constructed with null function pointer deleter"); - } + public: + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + static_assert(is_default_constructible::value, + "unique_ptr::deleter_type is not default constructible"); + } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) + { + static_assert(!is_pointer::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::value, + "unique_ptr constructed with null function pointer deleter"); + } - __WI_LIBCPP_INLINE_VISIBILITY - operator __rv() - { - return __rv(*this); - } + __WI_LIBCPP_INLINE_VISIBILITY + operator __rv() + { + return __rv(*this); + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(__rv __u) : __ptr_(__u->release(), wistd::forward(__u->get_deleter())) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) : __ptr_(__u->release(), wistd::forward(__u->get_deleter())) + { + } - template - __WI_LIBCPP_INLINE_VISIBILITY typename enable_if< - !is_array<_Up>::value && is_convertible::pointer, pointer>::value && is_assignable::value, - unique_ptr&>::type - operator=(unique_ptr<_Up, _Ep> __u) - { - reset(__u.release()); - __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); - return *this; - } + template + __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if::value && + is_convertible::pointer, pointer>::value && + is_assignable::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)) - { - } + __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() + { + reset(); + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(nullptr_t) WI_NOEXCEPT - { - reset(); - return *this; - } + __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_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 + 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 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 __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 __ptr_; - - template - struct _CheckArrayPointerConversion : is_same<_From, pointer> - { + __WI_LIBCPP_INLINE_VISIBILITY + void swap(unique_ptr &__u) WI_NOEXCEPT + { + __ptr_.swap(__u.__ptr_); + } }; - template - struct _CheckArrayPointerConversion<_FromElem*> - : integral_constant< - bool, - is_same<_FromElem*, pointer>::value || - (is_same::value && is_convertible<_FromElem (*)[], element_type (*)[]>::value)> + template 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 __ptr_; + + template struct _CheckArrayPointerConversion : is_same<_From, pointer> + { + }; + + template + struct _CheckArrayPointerConversion<_FromElem *> + : integral_constant::value || + (is_same::value && + is_convertible<_FromElem (*)[], element_type (*)[]>::value)> + { + }; #ifndef __WI_LIBCPP_CXX03_LANG - using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; + using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; - template - using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; + template using _LValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; - template - using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; + template + using _GoodRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; - template - using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; + template + using _BadRValRefType = typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; - template , _Dummy>::type> - using _EnableIfDeleterDefaultConstructible = - typename enable_if::value && !is_pointer<_Deleter>::value>::type; + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && !is_pointer<_Deleter>::value>::type; - template - using _EnableIfDeleterConstructible = typename enable_if::value>::type; + template + using _EnableIfDeleterConstructible = typename enable_if::value>::type; - template - using _EnableIfPointerConvertible = typename enable_if<_CheckArrayPointerConversion<_Pp>::value>::type; + template + using _EnableIfPointerConvertible = typename enable_if<_CheckArrayPointerConversion<_Pp>::value>::type; - template - using _EnableIfMoveConvertible = typename enable_if< - is_array<_Up>::value && is_same::value && is_same::value && - is_convertible<_ElemT (*)[], element_type (*)[]>::value>::type; + template + using _EnableIfMoveConvertible = + typename enable_if::value && is_same::value && + is_same::value && + is_convertible<_ElemT (*)[], element_type (*)[]>::value>::type; - template - 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 + 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 - using _EnableIfDeleterAssignable = typename enable_if::value>::type; + template + using _EnableIfDeleterAssignable = typename enable_if::value>::type; -public: - template > - __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) - { - } + public: + template > + __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) + { + } - template > - __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) - { - } + template > + __WI_LIBCPP_INLINE_VISIBILITY constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) + { + } - template , class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(_Pp __p) WI_NOEXCEPT : __ptr_(__p) - { - } + template , + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY explicit unique_ptr(_Pp __p) WI_NOEXCEPT : __ptr_(__p) + { + } - template >, class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d) - { - } + template >, + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(__p, __d) + { + } - template >> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(nullptr, __d) - { - } + template >> + __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(nullptr, __d) + { + } - template >, 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::value, "rvalue deleter bound to reference"); - } + template >, + 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::value, "rvalue deleter bound to reference"); + } - template >> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT : __ptr_(nullptr, wistd::move(__d)) - { - static_assert(!is_reference::value, "rvalue deleter bound to reference"); - } + template >> + __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(nullptr, wistd::move(__d)) + { + static_assert(!is_reference::value, "rvalue deleter bound to reference"); + } - template >, class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete; + template >, + 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(__u.get_deleter())) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr &&__u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) + { + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = wistd::forward(__u.get_deleter()); - return *this; - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr &operator=(unique_ptr &&__u) WI_NOEXCEPT + { + reset(__u.release()); + __ptr_.second() = wistd::forward(__u.get_deleter()); + return *this; + } - template , _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 , _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 , _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; - } + template , _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 - explicit unique_ptr(_Up); + private: + template explicit unique_ptr(_Up); - unique_ptr(unique_ptr&); - template - unique_ptr(unique_ptr<_Up>&); + unique_ptr(unique_ptr &); + template unique_ptr(unique_ptr<_Up> &); - unique_ptr& operator=(unique_ptr&); - template - unique_ptr& operator=(unique_ptr<_Up>&); + unique_ptr &operator=(unique_ptr &); + template unique_ptr &operator=(unique_ptr<_Up> &); - template - unique_ptr( - _Up __u, - typename conditional::value, deleter_type, typename add_lvalue_reference::type>::type, - typename enable_if::value, __nat>::type = __nat()); + template + unique_ptr(_Up __u, + typename conditional::value, deleter_type, + typename add_lvalue_reference::type>::type, + typename enable_if::value, __nat>::type = __nat()); -public: - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr() : __ptr_(pointer()) - { - static_assert(!is_pointer::value, "unique_ptr constructed with null function pointer deleter"); - } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t) : __ptr_(pointer()) - { - static_assert(!is_pointer::value, "unique_ptr constructed with null function pointer deleter"); - } + public: + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } - __WI_LIBCPP_INLINE_VISIBILITY - explicit unique_ptr(pointer __p) : __ptr_(__p) - { - static_assert(!is_pointer::value, "unique_ptr constructed with null function pointer deleter"); - } + __WI_LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) : __ptr_(__p) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, deleter_type __d) : __ptr_(__p, wistd::forward(__d)) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) : __ptr_(__p, wistd::forward(__d)) + { + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t, deleter_type __d) : __ptr_(pointer(), wistd::forward(__d)) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, deleter_type __d) : __ptr_(pointer(), wistd::forward(__d)) + { + } - __WI_LIBCPP_INLINE_VISIBILITY - operator __rv() - { - return __rv(*this); - } + __WI_LIBCPP_INLINE_VISIBILITY + operator __rv() + { + return __rv(*this); + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(__rv __u) : __ptr_(__u->release(), wistd::forward(__u->get_deleter())) - { - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) : __ptr_(__u->release(), wistd::forward(__u->get_deleter())) + { + } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(__rv __u) - { - reset(__u->release()); - __ptr_.second() = wistd::forward(__u->get_deleter()); - return *this; - } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr &operator=(__rv __u) + { + reset(__u->release()); + __ptr_.second() = wistd::forward(__u->get_deleter()); + return *this; + } #endif // __WI_LIBCPP_CXX03_LANG -public: - __WI_LIBCPP_INLINE_VISIBILITY - ~unique_ptr() + 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 + __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 + 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 { - reset(); + __x.swap(__y); } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(nullptr_t) WI_NOEXCEPT + template + 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 { - reset(); - return *this; + __x.swap(__y); } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator[](size_t __i) const + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - return __ptr_.first()[__i]; - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY pointer get() const WI_NOEXCEPT - { - return __ptr_.first(); + return __x.get() == __y.get(); } - __WI_LIBCPP_INLINE_VISIBILITY - deleter_type& get_deleter() WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - return __ptr_.second(); + return !(__x == __y); } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY const deleter_type& get_deleter() const WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - return __ptr_.second(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT - { - return __ptr_.first() != nullptr; + 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()); } - __WI_LIBCPP_INLINE_VISIBILITY - pointer release() WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - pointer __t = __ptr_.first(); - __ptr_.first() = pointer(); - return __t; + return __y < __x; } - template - __WI_LIBCPP_INLINE_VISIBILITY typename enable_if<_CheckArrayPointerConversion<_Pp>::value>::type reset(_Pp __p) WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - pointer __tmp = __ptr_.first(); - __ptr_.first() = __p; - if (__tmp) - __ptr_.second()(__tmp); + return !(__y < __x); } - __WI_LIBCPP_INLINE_VISIBILITY - void reset(nullptr_t = nullptr) WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1> &__x, + const unique_ptr<_T2, _D2> &__y) { - pointer __tmp = __ptr_.first(); - __ptr_.first() = nullptr; - if (__tmp) - __ptr_.second()(__tmp); + return !(__x < __y); } - __WI_LIBCPP_INLINE_VISIBILITY - void swap(unique_ptr& __u) WI_NOEXCEPT + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const unique_ptr<_T1, _D1> &__x, nullptr_t) WI_NOEXCEPT { - __ptr_.swap(__u.__ptr_); + return !__x; } -}; -// Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work -template -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 + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const unique_ptr<_T1, _D1> &__x) WI_NOEXCEPT + { + return !__x; + } -template -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 + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1> &__x, nullptr_t) WI_NOEXCEPT + { + return static_cast(__x); + } -template -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 + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const unique_ptr<_T1, _D1> &__x) WI_NOEXCEPT + { + return static_cast(__x); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) -{ - return !(__x == __y); -} + template + 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 -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 + 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 -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) -{ - return __y < __x; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1> &__x, nullptr_t) + { + return nullptr < __x; + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) -{ - return !(__y < __x); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(nullptr_t, const unique_ptr<_T1, _D1> &__x) + { + return __x < nullptr; + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) -{ - return !(__x < __y); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1> &__x, nullptr_t) + { + return !(nullptr < __x); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT -{ - return !__x; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(nullptr_t, const unique_ptr<_T1, _D1> &__x) + { + return !(__x < nullptr); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT -{ - return !__x; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1> &__x, nullptr_t) + { + return !(__x < nullptr); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT -{ - return static_cast(__x); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT -{ - return static_cast(__x); -} - -template -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 -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 -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(const unique_ptr<_T1, _D1>& __x, nullptr_t) -{ - return nullptr < __x; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>(nullptr_t, const unique_ptr<_T1, _D1>& __x) -{ - return __x < nullptr; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(const unique_ptr<_T1, _D1>& __x, nullptr_t) -{ - return !(nullptr < __x); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator<=(nullptr_t, const unique_ptr<_T1, _D1>& __x) -{ - return !(__x < nullptr); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(const unique_ptr<_T1, _D1>& __x, nullptr_t) -{ - return !(__x < nullptr); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY bool operator>=(nullptr_t, const unique_ptr<_T1, _D1>& __x) -{ - return !(nullptr < __x); -} + template + 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 -inline __WI_LIBCPP_INLINE_VISIBILITY unique_ptr<_Tp, _Dp> move(unique_ptr<_Tp, _Dp>& __t) -{ - return unique_ptr<_Tp, _Dp>(__rv>(__t)); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY unique_ptr<_Tp, _Dp> move(unique_ptr<_Tp, _Dp> &__t) + { + return unique_ptr<_Tp, _Dp>(__rv>(__t)); + } #endif } // namespace wistd diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_type_traits.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_type_traits.h index 0fb49ab..f0eb31d 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_type_traits.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wistd_type_traits.h @@ -45,1011 +45,875 @@ /// @cond namespace wistd // ("Windows Implementation" std) { -template -struct __WI_LIBCPP_TEMPLATE_VIS pair; -template -class __WI_LIBCPP_TEMPLATE_VIS reference_wrapper; -template -struct __WI_LIBCPP_TEMPLATE_VIS hash; + template struct __WI_LIBCPP_TEMPLATE_VIS pair; + template class __WI_LIBCPP_TEMPLATE_VIS reference_wrapper; + template struct __WI_LIBCPP_TEMPLATE_VIS hash; -template -struct __void_t -{ - typedef void type; -}; + template struct __void_t + { + typedef void type; + }; -template -struct __identity -{ - typedef _Tp type; -}; + template struct __identity + { + typedef _Tp type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS conditional -{ - typedef _If type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS conditional -{ - typedef _Then type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS conditional + { + typedef _If type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS conditional + { + typedef _Then type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using conditional_t = typename conditional<_Bp, _If, _Then>::type; + template using conditional_t = typename conditional<_Bp, _If, _Then>::type; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if{}; -template -struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if -{ - typedef typename _Tp::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if{}; + template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if + { + typedef typename _Tp::type type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS enable_if{}; -template -struct __WI_LIBCPP_TEMPLATE_VIS enable_if -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS enable_if{}; + template struct __WI_LIBCPP_TEMPLATE_VIS enable_if + { + typedef _Tp type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using enable_if_t = typename enable_if<_Bp, _Tp>::type; + template using enable_if_t = typename enable_if<_Bp, _Tp>::type; #endif // addressof #ifndef __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF -template -inline __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY _Tp* addressof(_Tp& __x) WI_NOEXCEPT -{ - return __builtin_addressof(__x); -} + template + inline __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY _Tp *addressof(_Tp &__x) + WI_NOEXCEPT + { + return __builtin_addressof(__x); + } #else -template -inline __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY _Tp* addressof(_Tp& __x) WI_NOEXCEPT -{ - return reinterpret_cast<_Tp*>(const_cast(&reinterpret_cast(__x))); -} + template inline __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY _Tp *addressof(_Tp &__x) WI_NOEXCEPT + { + return reinterpret_cast<_Tp *>(const_cast(&reinterpret_cast(__x))); + } #endif // __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF #if !defined(__WI_LIBCPP_CXX03_LANG) -template -_Tp* addressof(const _Tp&&) WI_NOEXCEPT = delete; + template _Tp *addressof(const _Tp &&) WI_NOEXCEPT = delete; #endif -struct __two -{ - char __lx[2]; -}; - -// helper class: - -template -struct __WI_LIBCPP_TEMPLATE_VIS integral_constant -{ - static __WI_LIBCPP_CONSTEXPR const _Tp value = __v; - typedef _Tp value_type; - typedef integral_constant type; - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR operator value_type() const WI_NOEXCEPT + struct __two { - return value; - } + char __lx[2]; + }; + + // helper class: + + template struct __WI_LIBCPP_TEMPLATE_VIS integral_constant + { + static __WI_LIBCPP_CONSTEXPR const _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant type; + __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + operator value_type() const WI_NOEXCEPT + { + return value; + } #if __WI_LIBCPP_STD_VER > 11 - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY constexpr value_type operator()() const WI_NOEXCEPT - { - return value; - } + __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY constexpr value_type operator()() const + WI_NOEXCEPT + { + return value; + } #endif -}; + }; -template -__WI_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; + template __WI_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; #if !defined(__WI_LIBCPP_CXX03_LANG) -template -using bool_constant = integral_constant; + template using bool_constant = integral_constant; #define __WI_LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)> #else #define __WI_LIBCPP_BOOL_CONSTANT(__b) integral_constant #endif -typedef __WI_LIBCPP_BOOL_CONSTANT(true) true_type; -typedef __WI_LIBCPP_BOOL_CONSTANT(false) false_type; + typedef __WI_LIBCPP_BOOL_CONSTANT(true) true_type; + typedef __WI_LIBCPP_BOOL_CONSTANT(false) false_type; #if !defined(__WI_LIBCPP_CXX03_LANG) -// __lazy_and + // __lazy_and -template -struct __lazy_and_impl; + template struct __lazy_and_impl; -template -struct __lazy_and_impl : false_type -{ -}; + template struct __lazy_and_impl : false_type + { + }; -template <> -struct __lazy_and_impl : true_type -{ -}; + template <> struct __lazy_and_impl : true_type + { + }; -template -struct __lazy_and_impl : integral_constant -{ -}; + template struct __lazy_and_impl : integral_constant + { + }; -template -struct __lazy_and_impl : __lazy_and_impl<_Hp::type::value, _Tp...> -{ -}; + template + struct __lazy_and_impl : __lazy_and_impl<_Hp::type::value, _Tp...> + { + }; -template -struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> -{ -}; + template struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> + { + }; -// __lazy_or + // __lazy_or -template -struct __lazy_or_impl; + template struct __lazy_or_impl; -template -struct __lazy_or_impl : true_type -{ -}; + template struct __lazy_or_impl : true_type + { + }; -template <> -struct __lazy_or_impl : false_type -{ -}; + template <> struct __lazy_or_impl : false_type + { + }; -template -struct __lazy_or_impl : __lazy_or_impl<_Hp::type::value, _Tp...> -{ -}; + template + struct __lazy_or_impl : __lazy_or_impl<_Hp::type::value, _Tp...> + { + }; -template -struct __lazy_or : __lazy_or_impl<_P1::type::value, _Pr...> -{ -}; + template struct __lazy_or : __lazy_or_impl<_P1::type::value, _Pr...> + { + }; -// __lazy_not + // __lazy_not -template -struct __lazy_not : integral_constant -{ -}; + template struct __lazy_not : integral_constant + { + }; -// __and_ -template -struct __and_; -template <> -struct __and_<> : true_type -{ -}; + // __and_ + template struct __and_; + template <> struct __and_<> : true_type + { + }; -template -struct __and_<_B0> : _B0 -{ -}; + template struct __and_<_B0> : _B0 + { + }; -template -struct __and_<_B0, _B1> : conditional<_B0::value, _B1, _B0>::type -{ -}; + template struct __and_<_B0, _B1> : conditional<_B0::value, _B1, _B0>::type + { + }; -template -struct __and_<_B0, _B1, _B2, _Bn...> : conditional<_B0::value, __and_<_B1, _B2, _Bn...>, _B0>::type -{ -}; + template + struct __and_<_B0, _B1, _B2, _Bn...> : conditional<_B0::value, __and_<_B1, _B2, _Bn...>, _B0>::type + { + }; -// __or_ -template -struct __or_; -template <> -struct __or_<> : false_type -{ -}; + // __or_ + template struct __or_; + template <> struct __or_<> : false_type + { + }; -template -struct __or_<_B0> : _B0 -{ -}; + template struct __or_<_B0> : _B0 + { + }; -template -struct __or_<_B0, _B1> : conditional<_B0::value, _B0, _B1>::type -{ -}; + template struct __or_<_B0, _B1> : conditional<_B0::value, _B0, _B1>::type + { + }; -template -struct __or_<_B0, _B1, _B2, _Bn...> : conditional<_B0::value, _B0, __or_<_B1, _B2, _Bn...>>::type -{ -}; + template + struct __or_<_B0, _B1, _B2, _Bn...> : conditional<_B0::value, _B0, __or_<_B1, _B2, _Bn...>>::type + { + }; -// __not_ -template -struct __not_ : conditional<_Tp::value, false_type, true_type>::type -{ -}; + // __not_ + template struct __not_ : conditional<_Tp::value, false_type, true_type>::type + { + }; #endif // !defined(__WI_LIBCPP_CXX03_LANG) -// is_const + // is_const -template -struct __WI_LIBCPP_TEMPLATE_VIS is_const : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_const : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_const_v = is_const<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_const_v = is_const<_Tp>::value; #endif -// is_volatile + // is_volatile -template -struct __WI_LIBCPP_TEMPLATE_VIS is_volatile : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_volatile<_Tp volatile> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile<_Tp volatile> : public true_type + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_volatile_v = is_volatile<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_volatile_v = is_volatile<_Tp>::value; #endif -// remove_const + // remove_const -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_const -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_const -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_const + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_const + { + typedef _Tp type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_const_t = typename remove_const<_Tp>::type; + template using remove_const_t = typename remove_const<_Tp>::type; #endif -// remove_volatile + // remove_volatile -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile + { + typedef _Tp type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_volatile_t = typename remove_volatile<_Tp>::type; + template using remove_volatile_t = typename remove_volatile<_Tp>::type; #endif -// remove_cv + // remove_cv -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_cv -{ - typedef typename remove_volatile::type>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_cv + { + typedef typename remove_volatile::type>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_cv_t = typename remove_cv<_Tp>::type; + template using remove_cv_t = typename remove_cv<_Tp>::type; #endif -// is_void + // is_void -template -struct __libcpp_is_void : public false_type -{ -}; -template <> -struct __libcpp_is_void : public true_type -{ -}; + template struct __libcpp_is_void : public false_type + { + }; + template <> struct __libcpp_is_void : public true_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_void : public __libcpp_is_void::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_void : public __libcpp_is_void::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v = is_void<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v = is_void<_Tp>::value; #endif -// __is_nullptr_t + // __is_nullptr_t -template -struct __is_nullptr_t_impl : public false_type -{ -}; -template <> -struct __is_nullptr_t_impl : public true_type -{ -}; + template struct __is_nullptr_t_impl : public false_type + { + }; + template <> struct __is_nullptr_t_impl : public true_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t : public __is_nullptr_t_impl::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t : public __is_nullptr_t_impl::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 -template -struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer : public __is_nullptr_t_impl::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer : public __is_nullptr_t_impl::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_null_pointer_v = is_null_pointer<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_null_pointer_v = is_null_pointer<_Tp>::value; #endif #endif -// is_integral + // is_integral -template -struct __libcpp_is_integral : public false_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; + template struct __libcpp_is_integral : public false_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; #ifdef _MSC_VER -template <> -struct __libcpp_is_integral<__wchar_t> : public true_type -{ -}; + template <> struct __libcpp_is_integral<__wchar_t> : public true_type + { + }; #else -template <> -struct __libcpp_is_integral : public true_type -{ -}; + template <> struct __libcpp_is_integral : public true_type + { + }; #endif #ifndef __WI_LIBCPP_HAS_NO_UNICODE_CHARS -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; #endif // __WI_LIBCPP_HAS_NO_UNICODE_CHARS -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; -template <> -struct __libcpp_is_integral : public true_type -{ -}; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; + template <> struct __libcpp_is_integral : public true_type + { + }; #ifndef __WI_LIBCPP_HAS_NO_INT128 -template <> -struct __libcpp_is_integral<__int128_t> : public true_type -{ -}; -template <> -struct __libcpp_is_integral<__uint128_t> : public true_type -{ -}; + template <> struct __libcpp_is_integral<__int128_t> : public true_type + { + }; + template <> struct __libcpp_is_integral<__uint128_t> : public true_type + { + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS is_integral : public __libcpp_is_integral::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_integral : public __libcpp_is_integral::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_integral_v = is_integral<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_integral_v = is_integral<_Tp>::value; #endif -// is_floating_point + // is_floating_point -template -struct __libcpp_is_floating_point : public false_type -{ -}; -template <> -struct __libcpp_is_floating_point : public true_type -{ -}; -template <> -struct __libcpp_is_floating_point : public true_type -{ -}; -template <> -struct __libcpp_is_floating_point : public true_type -{ -}; + template struct __libcpp_is_floating_point : public false_type + { + }; + template <> struct __libcpp_is_floating_point : public true_type + { + }; + template <> struct __libcpp_is_floating_point : public true_type + { + }; + template <> struct __libcpp_is_floating_point : public true_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_floating_point : public __libcpp_is_floating_point::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_floating_point : public __libcpp_is_floating_point::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_floating_point_v = is_floating_point<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_floating_point_v = is_floating_point<_Tp>::value; #endif -// is_array + // is_array -template -struct __WI_LIBCPP_TEMPLATE_VIS is_array : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[]> : public true_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[_Np]> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_array : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[]> : public true_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[_Np]> : public true_type + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_array_v = is_array<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_array_v = is_array<_Tp>::value; #endif -// is_pointer + // is_pointer -template -struct __libcpp_is_pointer : public false_type -{ -}; -template -struct __libcpp_is_pointer<_Tp*> : public true_type -{ -}; + template struct __libcpp_is_pointer : public false_type + { + }; + template struct __libcpp_is_pointer<_Tp *> : public true_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_pointer : public __libcpp_is_pointer::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_pointer : public __libcpp_is_pointer::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pointer_v = is_pointer<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pointer_v = is_pointer<_Tp>::value; #endif -// is_reference + // is_reference -template -struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference<_Tp&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference<_Tp &> : public true_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference : public false_type + { + }; #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference<_Tp&&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference<_Tp &&> : public true_type + { + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS is_reference : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp &> : public true_type + { + }; #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp &&> : public true_type + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_reference_v = is_reference<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_reference_v = is_reference<_Tp>::value; -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_lvalue_reference_v = is_lvalue_reference<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_lvalue_reference_v = is_lvalue_reference<_Tp>::value; -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_rvalue_reference_v = is_rvalue_reference<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_rvalue_reference_v = is_rvalue_reference<_Tp>::value; #endif -// is_union + // is_union #if __WI_HAS_FEATURE_IS_UNION || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_union : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_union : public integral_constant + { + }; #else -template -struct __libcpp_union : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_union : public __libcpp_union::type> -{ -}; + template struct __libcpp_union : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_union : public __libcpp_union::type> + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_union_v = is_union<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_union_v = is_union<_Tp>::value; #endif -// is_class + // is_class #if __WI_HAS_FEATURE_IS_CLASS || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_class : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_class : public integral_constant + { + }; #else -namespace __is_class_imp -{ + namespace __is_class_imp + { + template char __test(int _Tp::*); + template __two __test(...); + } // namespace __is_class_imp + template - char __test(int _Tp::*); - template - __two __test(...); -} // namespace __is_class_imp - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_class - : public integral_constant(0)) == 1 && !is_union<_Tp>::value> -{ -}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_class_v = is_class<_Tp>::value; -#endif - -// is_same - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_same : public false_type -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_same<_Tp, _Tp> : public true_type -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_same_v = is_same<_Tp, _Up>::value; -#endif - -// is_function - -namespace __libcpp_is_function_imp -{ - struct __dummy_type + struct __WI_LIBCPP_TEMPLATE_VIS is_class + : public integral_constant(0)) == 1 && !is_union<_Tp>::value> { }; - template - char __test(_Tp*); - template - char __test(__dummy_type); - template - __two __test(...); - template - _Tp& __source(int); - template - __dummy_type __source(...); -} // namespace __libcpp_is_function_imp -template ::value || is_union<_Tp>::value || is_void<_Tp>::value || is_reference<_Tp>::value || __is_nullptr_t<_Tp>::value> -struct __libcpp_is_function - : public integral_constant(__libcpp_is_function_imp::__source<_Tp>(0))) == 1> -{ -}; -template -struct __libcpp_is_function<_Tp, true> : public false_type -{ -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_function : public __libcpp_is_function<_Tp> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_function_v = is_function<_Tp>::value; #endif -// is_member_function_pointer - -// template struct __libcpp_is_member_function_pointer : public false_type {}; -// template struct __libcpp_is_member_function_pointer<_Tp _Up::*> : public is_function<_Tp> {}; -// - -template -struct __member_pointer_traits_imp -{ // forward declaration; specializations later -}; - -template -struct __libcpp_is_member_function_pointer : public false_type -{ -}; - -template -struct __libcpp_is_member_function_pointer<_Ret _Class::*> : public is_function<_Ret> -{ -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_member_function_pointer - : public __libcpp_is_member_function_pointer::type>::type -{ -}; - #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_function_pointer_v = is_member_function_pointer<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_class_v = is_class<_Tp>::value; #endif -// is_member_pointer + // is_same -template -struct __libcpp_is_member_pointer : public false_type -{ -}; -template -struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type -{ -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_member_pointer : public __libcpp_is_member_pointer::type> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_same : public false_type + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS is_same<_Tp, _Tp> : public true_type + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_pointer_v = is_member_pointer<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_same_v = is_same<_Tp, _Up>::value; #endif -// is_member_object_pointer + // is_function -template -struct __WI_LIBCPP_TEMPLATE_VIS is_member_object_pointer - : public integral_constant::value && !is_member_function_pointer<_Tp>::value> -{ -}; + namespace __libcpp_is_function_imp + { + struct __dummy_type + { + }; + template char __test(_Tp *); + template char __test(__dummy_type); + template __two __test(...); + template _Tp &__source(int); + template __dummy_type __source(...); + } // namespace __libcpp_is_function_imp + + template ::value || is_union<_Tp>::value || is_void<_Tp>::value || + is_reference<_Tp>::value || __is_nullptr_t<_Tp>::value> + struct __libcpp_is_function : public integral_constant( + __libcpp_is_function_imp::__source<_Tp>(0))) == 1> + { + }; + template struct __libcpp_is_function<_Tp, true> : public false_type + { + }; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_function : public __libcpp_is_function<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_object_pointer_v = is_member_object_pointer<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_function_v = is_function<_Tp>::value; #endif -// is_enum + // is_member_function_pointer + + // template struct __libcpp_is_member_function_pointer : public false_type {}; + // template struct __libcpp_is_member_function_pointer<_Tp _Up::*> : public is_function<_Tp> + // {}; + // + + template struct __member_pointer_traits_imp + { // forward declaration; specializations later + }; + + template struct __libcpp_is_member_function_pointer : public false_type + { + }; + + template + struct __libcpp_is_member_function_pointer<_Ret _Class::*> : public is_function<_Ret> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_member_function_pointer + : public __libcpp_is_member_function_pointer::type>::type + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_function_pointer_v = + is_member_function_pointer<_Tp>::value; +#endif + + // is_member_pointer + + template struct __libcpp_is_member_pointer : public false_type + { + }; + template struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_member_pointer : public __libcpp_is_member_pointer::type> + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_pointer_v = is_member_pointer<_Tp>::value; +#endif + + // is_member_object_pointer + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_member_object_pointer + : public integral_constant::value && !is_member_function_pointer<_Tp>::value> + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_object_pointer_v = is_member_object_pointer<_Tp>::value; +#endif + + // is_enum #if __WI_HAS_FEATURE_IS_ENUM || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_enum : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_enum : public integral_constant + { + }; #else -template -struct __WI_LIBCPP_TEMPLATE_VIS is_enum - : public integral_constant< - bool, - !is_void<_Tp>::value && !is_integral<_Tp>::value && !is_floating_point<_Tp>::value && !is_array<_Tp>::value && - !is_pointer<_Tp>::value && !is_reference<_Tp>::value && !is_member_pointer<_Tp>::value && !is_union<_Tp>::value && - !is_class<_Tp>::value && !is_function<_Tp>::value> -{ -}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_enum_v = is_enum<_Tp>::value; -#endif - -// is_arithmetic - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_arithmetic : public integral_constant::value || is_floating_point<_Tp>::value> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_arithmetic_v = is_arithmetic<_Tp>::value; -#endif - -// is_fundamental - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_fundamental - : public integral_constant::value || __is_nullptr_t<_Tp>::value || is_arithmetic<_Tp>::value> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_fundamental_v = is_fundamental<_Tp>::value; -#endif - -// is_scalar - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_scalar - : public integral_constant::value || is_member_pointer<_Tp>::value || is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value || is_enum<_Tp>::value> -{ -}; - -template <> -struct __WI_LIBCPP_TEMPLATE_VIS is_scalar : public true_type -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_scalar_v = is_scalar<_Tp>::value; -#endif - -// is_object - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_object - : public integral_constant::value || is_array<_Tp>::value || is_union<_Tp>::value || is_class<_Tp>::value> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_object_v = is_object<_Tp>::value; -#endif - -// is_compound - -template -struct __WI_LIBCPP_TEMPLATE_VIS is_compound : public integral_constant::value> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_compound_v = is_compound<_Tp>::value; -#endif - -// __is_referenceable [defns.referenceable] - -struct __is_referenceable_impl -{ template - static _Tp& __test(int); + struct __WI_LIBCPP_TEMPLATE_VIS is_enum + : public integral_constant::value && !is_integral<_Tp>::value && + !is_floating_point<_Tp>::value && !is_array<_Tp>::value && + !is_pointer<_Tp>::value && !is_reference<_Tp>::value && + !is_member_pointer<_Tp>::value && !is_union<_Tp>::value && + !is_class<_Tp>::value && !is_function<_Tp>::value> + { + }; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_enum_v = is_enum<_Tp>::value; +#endif + + // is_arithmetic + template - static __two __test(...); -}; + struct __WI_LIBCPP_TEMPLATE_VIS is_arithmetic + : public integral_constant::value || is_floating_point<_Tp>::value> + { + }; -template -struct __is_referenceable : integral_constant(0)), __two>::value>{}; - -// add_const - -template ::value || is_function<_Tp>::value || is_const<_Tp>::value> -struct __add_const -{ - typedef _Tp type; -}; - -template -struct __add_const<_Tp, false> -{ - typedef const _Tp type; -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS add_const -{ - typedef typename __add_const<_Tp>::type type; -}; - -#if __WI_LIBCPP_STD_VER > 11 -template -using add_const_t = typename add_const<_Tp>::type; +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_arithmetic_v = is_arithmetic<_Tp>::value; #endif -// add_volatile + // is_fundamental -template ::value || is_function<_Tp>::value || is_volatile<_Tp>::value> -struct __add_volatile -{ - typedef _Tp type; -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_fundamental + : public integral_constant::value || __is_nullptr_t<_Tp>::value || is_arithmetic<_Tp>::value> + { + }; -template -struct __add_volatile<_Tp, false> -{ - typedef volatile _Tp type; -}; - -template -struct __WI_LIBCPP_TEMPLATE_VIS add_volatile -{ - typedef typename __add_volatile<_Tp>::type type; -}; - -#if __WI_LIBCPP_STD_VER > 11 -template -using add_volatile_t = typename add_volatile<_Tp>::type; +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_fundamental_v = is_fundamental<_Tp>::value; #endif -// add_cv + // is_scalar -template -struct __WI_LIBCPP_TEMPLATE_VIS add_cv -{ - typedef typename add_const::type>::type type; -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_scalar + : public integral_constant::value || is_member_pointer<_Tp>::value || + is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value || + is_enum<_Tp>::value> + { + }; -#if __WI_LIBCPP_STD_VER > 11 -template -using add_cv_t = typename add_cv<_Tp>::type; + template <> struct __WI_LIBCPP_TEMPLATE_VIS is_scalar : public true_type + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_scalar_v = is_scalar<_Tp>::value; #endif -// remove_reference + // is_object -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_reference -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&> -{ - typedef _Tp type; -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_object + : public integral_constant::value || is_array<_Tp>::value || is_union<_Tp>::value || + is_class<_Tp>::value> + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_object_v = is_object<_Tp>::value; +#endif + + // is_compound + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_compound : public integral_constant::value> + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_compound_v = is_compound<_Tp>::value; +#endif + + // __is_referenceable [defns.referenceable] + + struct __is_referenceable_impl + { + template static _Tp &__test(int); + template static __two __test(...); + }; + + template + struct __is_referenceable + : integral_constant(0)), __two>::value>{}; + + // add_const + + template ::value || is_function<_Tp>::value || is_const<_Tp>::value> + struct __add_const + { + typedef _Tp type; + }; + + template struct __add_const<_Tp, false> + { + typedef const _Tp type; + }; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_const + { + typedef typename __add_const<_Tp>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_const_t = typename add_const<_Tp>::type; +#endif + + // add_volatile + + template ::value || is_function<_Tp>::value || is_volatile<_Tp>::value> + struct __add_volatile + { + typedef _Tp type; + }; + + template struct __add_volatile<_Tp, false> + { + typedef volatile _Tp type; + }; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_volatile + { + typedef typename __add_volatile<_Tp>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_volatile_t = typename add_volatile<_Tp>::type; +#endif + + // add_cv + + template struct __WI_LIBCPP_TEMPLATE_VIS add_cv + { + typedef typename add_const::type>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_cv_t = typename add_cv<_Tp>::type; +#endif + + // remove_reference + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp &> + { + typedef _Tp type; + }; #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&&> -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp &&> + { + typedef _Tp type; + }; #endif #if __WI_LIBCPP_STD_VER > 11 -template -using remove_reference_t = typename remove_reference<_Tp>::type; + template using remove_reference_t = typename remove_reference<_Tp>::type; #endif -// add_lvalue_reference + // add_lvalue_reference -template ::value> -struct __add_lvalue_reference_impl -{ - typedef _Tp type; -}; -template -struct __add_lvalue_reference_impl<_Tp, true> -{ - typedef _Tp& type; -}; + template ::value> struct __add_lvalue_reference_impl + { + typedef _Tp type; + }; + template struct __add_lvalue_reference_impl<_Tp, true> + { + typedef _Tp &type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS add_lvalue_reference -{ - typedef typename __add_lvalue_reference_impl<_Tp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS add_lvalue_reference + { + typedef typename __add_lvalue_reference_impl<_Tp>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; + template using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; #endif #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template ::value> -struct __add_rvalue_reference_impl -{ - typedef _Tp type; -}; -template -struct __add_rvalue_reference_impl<_Tp, true> -{ - typedef _Tp&& type; -}; + template ::value> struct __add_rvalue_reference_impl + { + typedef _Tp type; + }; + template struct __add_rvalue_reference_impl<_Tp, true> + { + typedef _Tp &&type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS add_rvalue_reference -{ - typedef typename __add_rvalue_reference_impl<_Tp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS add_rvalue_reference + { + typedef typename __add_rvalue_reference_impl<_Tp>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; + template using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; #endif #endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -1058,2840 +922,2651 @@ using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; // MSVC has issues compiling some source code that uses the libc++ definition of 'declval' #ifdef _MSC_VER -template -typename add_rvalue_reference<_Tp>::type declval() WI_NOEXCEPT; + template typename add_rvalue_reference<_Tp>::type declval() WI_NOEXCEPT; #else -template -_Tp&& __declval(int); -template -_Tp __declval(long); + template _Tp &&__declval(int); + template _Tp __declval(long); -template -decltype(__declval<_Tp>(0)) declval() WI_NOEXCEPT; + template decltype(__declval<_Tp>(0)) declval() WI_NOEXCEPT; #endif #else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -typename add_lvalue_reference<_Tp>::type declval(); + template typename add_lvalue_reference<_Tp>::type declval(); #endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -// __uncvref + // __uncvref -template -struct __uncvref -{ - typedef typename remove_cv::type>::type type; -}; + template struct __uncvref + { + typedef typename remove_cv::type>::type type; + }; -template -struct __unconstref -{ - typedef typename remove_const::type>::type type; -}; + template struct __unconstref + { + typedef typename remove_const::type>::type type; + }; #ifndef __WI_LIBCPP_CXX03_LANG -template -using __uncvref_t = typename __uncvref<_Tp>::type; + template using __uncvref_t = typename __uncvref<_Tp>::type; #endif -// __is_same_uncvref + // __is_same_uncvref -template -struct __is_same_uncvref : is_same::type, typename __uncvref<_Up>::type> -{ -}; + template + struct __is_same_uncvref : is_same::type, typename __uncvref<_Up>::type> + { + }; #if __WI_LIBCPP_STD_VER > 17 -// remove_cvref - same as __uncvref -template -struct remove_cvref : public __uncvref<_Tp> -{ -}; + // remove_cvref - same as __uncvref + template struct remove_cvref : public __uncvref<_Tp> + { + }; -template -using remove_cvref_t = typename remove_cvref<_Tp>::type; + template using remove_cvref_t = typename remove_cvref<_Tp>::type; #endif -struct __any -{ - __any(...); -}; + struct __any + { + __any(...); + }; -// remove_pointer + // remove_pointer -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp*> -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const> -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* volatile> -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const volatile> -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp *> + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp *const> + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp *volatile> + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp *const volatile> + { + typedef _Tp type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_pointer_t = typename remove_pointer<_Tp>::type; + template using remove_pointer_t = typename remove_pointer<_Tp>::type; #endif -// add_pointer + // add_pointer -template ::value || is_same::type, void>::value> -struct __add_pointer_impl -{ - typedef typename remove_reference<_Tp>::type* type; -}; -template -struct __add_pointer_impl<_Tp, false> -{ - typedef _Tp type; -}; + template ::value || is_same::type, void>::value> + struct __add_pointer_impl + { + typedef typename remove_reference<_Tp>::type *type; + }; + template struct __add_pointer_impl<_Tp, false> + { + typedef _Tp type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS add_pointer -{ - typedef typename __add_pointer_impl<_Tp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS add_pointer + { + typedef typename __add_pointer_impl<_Tp>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using add_pointer_t = typename add_pointer<_Tp>::type; + template using add_pointer_t = typename add_pointer<_Tp>::type; #endif // type_identity #if __WI_LIBCPP_STD_VER > 17 -template -struct type_identity -{ - typedef _Tp type; -}; -template -using type_identity_t = typename type_identity<_Tp>::type; + template struct type_identity + { + typedef _Tp type; + }; + template using type_identity_t = typename type_identity<_Tp>::type; #endif -// is_signed + // is_signed -template ::value> -struct __libcpp_is_signed_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(-1) < _Tp(0)){}; + template ::value> + struct __libcpp_is_signed_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(-1) < _Tp(0)){}; -template -struct __libcpp_is_signed_impl<_Tp, false> : public true_type -{ -}; // floating point + template struct __libcpp_is_signed_impl<_Tp, false> : public true_type + { + }; // floating point -template ::value> -struct __libcpp_is_signed : public __libcpp_is_signed_impl<_Tp> -{ -}; + template ::value> + struct __libcpp_is_signed : public __libcpp_is_signed_impl<_Tp> + { + }; -template -struct __libcpp_is_signed<_Tp, false> : public false_type -{ -}; + template struct __libcpp_is_signed<_Tp, false> : public false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_signed : public __libcpp_is_signed<_Tp> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_signed : public __libcpp_is_signed<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_signed_v = is_signed<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_signed_v = is_signed<_Tp>::value; #endif -// is_unsigned + // is_unsigned -template ::value> -struct __libcpp_is_unsigned_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(0) < _Tp(-1)){}; + template ::value> + struct __libcpp_is_unsigned_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(0) < _Tp(-1)){}; -template -struct __libcpp_is_unsigned_impl<_Tp, false> : public false_type -{ -}; // floating point + template struct __libcpp_is_unsigned_impl<_Tp, false> : public false_type + { + }; // floating point -template ::value> -struct __libcpp_is_unsigned : public __libcpp_is_unsigned_impl<_Tp> -{ -}; + template ::value> + struct __libcpp_is_unsigned : public __libcpp_is_unsigned_impl<_Tp> + { + }; -template -struct __libcpp_is_unsigned<_Tp, false> : public false_type -{ -}; + template struct __libcpp_is_unsigned<_Tp, false> : public false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_unsigned : public __libcpp_is_unsigned<_Tp> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_unsigned : public __libcpp_is_unsigned<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_unsigned_v = is_unsigned<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_unsigned_v = is_unsigned<_Tp>::value; #endif -// rank + // rank -template -struct __WI_LIBCPP_TEMPLATE_VIS rank : public integral_constant -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[]> : public integral_constant::value + 1> -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[_Np]> : public integral_constant::value + 1> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS rank : public integral_constant + { + }; + template + struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[]> : public integral_constant::value + 1> + { + }; + template + struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[_Np]> : public integral_constant::value + 1> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t rank_v = rank<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t rank_v = rank<_Tp>::value; #endif -// extent + // extent -template -struct __WI_LIBCPP_TEMPLATE_VIS extent : public integral_constant -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], 0> : public integral_constant -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], _Ip> : public integral_constant::value> -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], 0> : public integral_constant -{ -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], _Ip> : public integral_constant::value> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS extent : public integral_constant + { + }; + template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], 0> : public integral_constant + { + }; + template + struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], _Ip> : public integral_constant::value> + { + }; + template + struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], 0> : public integral_constant + { + }; + template + struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], _Ip> + : public integral_constant::value> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t extent_v = extent<_Tp, _Ip>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t extent_v = extent<_Tp, _Ip>::value; #endif -// remove_extent + // remove_extent -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_extent -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[]> -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[_Np]> -{ - typedef _Tp type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[]> + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[_Np]> + { + typedef _Tp type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_extent_t = typename remove_extent<_Tp>::type; + template using remove_extent_t = typename remove_extent<_Tp>::type; #endif -// remove_all_extents + // remove_all_extents -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents -{ - typedef _Tp type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[]> -{ - typedef typename remove_all_extents<_Tp>::type type; -}; -template -struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[_Np]> -{ - typedef typename remove_all_extents<_Tp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents + { + typedef _Tp type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[]> + { + typedef typename remove_all_extents<_Tp>::type type; + }; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[_Np]> + { + typedef typename remove_all_extents<_Tp>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using remove_all_extents_t = typename remove_all_extents<_Tp>::type; + template using remove_all_extents_t = typename remove_all_extents<_Tp>::type; #endif -// decay + // decay -template -struct __decay -{ - typedef typename remove_cv<_Up>::type type; -}; + template struct __decay + { + typedef typename remove_cv<_Up>::type type; + }; -template -struct __decay<_Up, true> -{ -public: - typedef typename conditional< - is_array<_Up>::value, - typename remove_extent<_Up>::type*, - typename conditional::value, typename add_pointer<_Up>::type, typename remove_cv<_Up>::type>::type>::type type; -}; + template struct __decay<_Up, true> + { + public: + typedef typename conditional::value, typename remove_extent<_Up>::type *, + typename conditional::value, typename add_pointer<_Up>::type, + typename remove_cv<_Up>::type>::type>::type type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS decay -{ -private: - typedef typename remove_reference<_Tp>::type _Up; + template struct __WI_LIBCPP_TEMPLATE_VIS decay + { + private: + typedef typename remove_reference<_Tp>::type _Up; -public: - typedef typename __decay<_Up, __is_referenceable<_Up>::value>::type type; -}; + public: + typedef typename __decay<_Up, __is_referenceable<_Up>::value>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using decay_t = typename decay<_Tp>::type; + template using decay_t = typename decay<_Tp>::type; #endif -// is_abstract + // is_abstract -template -struct __WI_LIBCPP_TEMPLATE_VIS is_abstract : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_abstract : public integral_constant + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_abstract_v = is_abstract<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_abstract_v = is_abstract<_Tp>::value; #endif -// is_final + // is_final #if defined(__WI_LIBCPP_HAS_IS_FINAL) -template -struct __WI_LIBCPP_TEMPLATE_VIS __libcpp_is_final : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS __libcpp_is_final : public integral_constant + { + }; #else -template -struct __WI_LIBCPP_TEMPLATE_VIS __libcpp_is_final : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS __libcpp_is_final : public false_type + { + }; #endif #if defined(__WI_LIBCPP_HAS_IS_FINAL) && __WI_LIBCPP_STD_VER > 11 -template -struct __WI_LIBCPP_TEMPLATE_VIS is_final : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_final : public integral_constant + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_final_v = is_final<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_final_v = is_final<_Tp>::value; #endif // is_aggregate #if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_aggregate : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_aggregate : public integral_constant + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_aggregate_v = is_aggregate<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR constexpr bool is_aggregate_v = is_aggregate<_Tp>::value; #endif #endif // __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) -// is_base_of + // is_base_of #ifdef __WI_LIBCPP_HAS_IS_BASE_OF -template -struct __WI_LIBCPP_TEMPLATE_VIS is_base_of : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_base_of : public integral_constant + { + }; #else // __WI_LIBCPP_HAS_IS_BASE_OF -namespace __is_base_of_imp -{ - template - struct _Dst + namespace __is_base_of_imp { - _Dst(const volatile _Tp&); - }; - template - struct _Src - { - operator const volatile _Tp&(); - template - operator const _Dst<_Up>&(); - }; - template - struct __one - { - typedef char type; - }; - template - typename __one(declval<_Src<_Dp>>()))>::type __test(int); - template - __two __test(...); -} // namespace __is_base_of_imp + template struct _Dst + { + _Dst(const volatile _Tp &); + }; + template struct _Src + { + operator const volatile _Tp &(); + template operator const _Dst<_Up> &(); + }; + template struct __one + { + typedef char type; + }; + template typename __one(declval<_Src<_Dp>>()))>::type __test(int); + template __two __test(...); + } // namespace __is_base_of_imp -template -struct __WI_LIBCPP_TEMPLATE_VIS is_base_of - : public integral_constant::value && sizeof(__is_base_of_imp::__test<_Bp, _Dp>(0)) == 2> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_base_of + : public integral_constant::value && sizeof(__is_base_of_imp::__test<_Bp, _Dp>(0)) == 2> + { + }; #endif // __WI_LIBCPP_HAS_IS_BASE_OF #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_base_of_v = is_base_of<_Bp, _Dp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_base_of_v = is_base_of<_Bp, _Dp>::value; #endif -// is_convertible + // is_convertible #if __WI_HAS_FEATURE_IS_CONVERTIBLE_TO && !defined(__WI_LIBCPP_USE_IS_CONVERTIBLE_FALLBACK) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_convertible - : public integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_convertible + : public integral_constant::value> + { + }; #else // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO -namespace __is_convertible_imp -{ - template - void __test_convert(_Tp); - - template - struct __is_convertible_test : public false_type + namespace __is_convertible_imp { - }; + template void __test_convert(_Tp); - template - struct __is_convertible_test<_From, _To, decltype(__is_convertible_imp::__test_convert<_To>(declval<_From>()))> : public true_type - { - }; - - template ::value, bool _IsFunction = is_function<_Tp>::value, bool _IsVoid = is_void<_Tp>::value> - struct __is_array_function_or_void - { - enum + template struct __is_convertible_test : public false_type { - value = 0 }; - }; - template - struct __is_array_function_or_void<_Tp, true, false, false> - { - enum - { - value = 1 - }; - }; - template - struct __is_array_function_or_void<_Tp, false, true, false> - { - enum - { - value = 2 - }; - }; - template - struct __is_array_function_or_void<_Tp, false, false, true> - { - enum - { - value = 3 - }; - }; -} // namespace __is_convertible_imp -template ::type>::value> -struct __is_convertible_check -{ - static const size_t __v = 0; -}; + template + struct __is_convertible_test<_From, _To, decltype(__is_convertible_imp::__test_convert<_To>(declval<_From>()))> + : public true_type + { + }; -template -struct __is_convertible_check<_Tp, 0> -{ - static const size_t __v = sizeof(_Tp); -}; + template ::value, bool _IsFunction = is_function<_Tp>::value, + bool _IsVoid = is_void<_Tp>::value> + struct __is_array_function_or_void + { + enum + { + value = 0 + }; + }; + template struct __is_array_function_or_void<_Tp, true, false, false> + { + enum + { + value = 1 + }; + }; + template struct __is_array_function_or_void<_Tp, false, true, false> + { + enum + { + value = 2 + }; + }; + template struct __is_array_function_or_void<_Tp, false, false, true> + { + enum + { + value = 3 + }; + }; + } // namespace __is_convertible_imp -template < - class _T1, - class _T2, - unsigned _T1_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T1>::value, - unsigned _T2_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T2>::value> -struct __is_convertible - : public integral_constant< - bool, - __is_convertible_imp::__is_convertible_test<_T1, _T2>::value + template ::type>::value> + struct __is_convertible_check + { + static const size_t __v = 0; + }; + + template struct __is_convertible_check<_Tp, 0> + { + static const size_t __v = sizeof(_Tp); + }; + + template ::value, + unsigned _T2_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T2>::value> + struct __is_convertible + : public integral_constant< + bool, __is_convertible_imp::__is_convertible_test<_T1, _T2>::value #if defined(__WI_LIBCPP_HAS_NO_RVALUE_REFERENCES) - && !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value && - (!is_const::type>::value || is_volatile::type>::value) && - (is_same::type, typename remove_cv::type>::type>::value || - is_base_of::type, _T1>::value)) + && !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value && + (!is_const::type>::value || + is_volatile::type>::value) && + (is_same::type, + typename remove_cv::type>::type>::value || + is_base_of::type, _T1>::value)) #endif - >{}; + >{}; -template -struct __is_convertible<_T1, _T2, 0, 1> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 1, 1> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 2, 1> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 3, 1> : public false_type{}; + template struct __is_convertible<_T1, _T2, 0, 1> : public false_type{}; + template struct __is_convertible<_T1, _T2, 1, 1> : public false_type{}; + template struct __is_convertible<_T1, _T2, 2, 1> : public false_type{}; + template struct __is_convertible<_T1, _T2, 3, 1> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 0, 2> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 1, 2> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 2, 2> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 3, 2> : public false_type{}; + template struct __is_convertible<_T1, _T2, 0, 2> : public false_type{}; + template struct __is_convertible<_T1, _T2, 1, 2> : public false_type{}; + template struct __is_convertible<_T1, _T2, 2, 2> : public false_type{}; + template struct __is_convertible<_T1, _T2, 3, 2> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 0, 3> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 1, 3> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 2, 3> : public false_type{}; -template -struct __is_convertible<_T1, _T2, 3, 3> : public true_type{}; + template struct __is_convertible<_T1, _T2, 0, 3> : public false_type{}; + template struct __is_convertible<_T1, _T2, 1, 3> : public false_type{}; + template struct __is_convertible<_T1, _T2, 2, 3> : public false_type{}; + template struct __is_convertible<_T1, _T2, 3, 3> : public true_type{}; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_convertible : public __is_convertible<_T1, _T2> -{ - static const size_t __complete_check1 = __is_convertible_check<_T1>::__v; - static const size_t __complete_check2 = __is_convertible_check<_T2>::__v; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_convertible : public __is_convertible<_T1, _T2> + { + static const size_t __complete_check1 = __is_convertible_check<_T1>::__v; + static const size_t __complete_check2 = __is_convertible_check<_T2>::__v; + }; #endif // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_convertible_v = is_convertible<_From, _To>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_convertible_v = is_convertible<_From, _To>::value; #endif -// is_empty + // is_empty #if __WI_HAS_FEATURE_IS_EMPTY || (__WI_GNUC_VER >= 407) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public integral_constant + { + }; #else // __WI_HAS_FEATURE_IS_EMPTY -template -struct __is_empty1 : public _Tp -{ - double __lx; -}; + template struct __is_empty1 : public _Tp + { + double __lx; + }; -struct __is_empty2 -{ - double __lx; -}; + struct __is_empty2 + { + double __lx; + }; -template ::value> -struct __libcpp_empty : public integral_constant) == sizeof(__is_empty2)> -{ -}; + template ::value> + struct __libcpp_empty : public integral_constant) == sizeof(__is_empty2)> + { + }; -template -struct __libcpp_empty<_Tp, false> : public false_type -{ -}; + template struct __libcpp_empty<_Tp, false> : public false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public __libcpp_empty<_Tp> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public __libcpp_empty<_Tp> + { + }; #endif // __WI_HAS_FEATURE_IS_EMPTY #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_empty_v = is_empty<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_empty_v = is_empty<_Tp>::value; #endif -// is_polymorphic + // is_polymorphic #if __WI_HAS_FEATURE_IS_POLYMORPHIC -template -struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic : public integral_constant + { + }; #else -template -char& __is_polymorphic_impl(typename enable_if(declval<_Tp*>())) != 0, int>::type); -template -__two& __is_polymorphic_impl(...); + template + char &__is_polymorphic_impl( + typename enable_if(declval<_Tp *>())) != 0, int>::type); + template __two &__is_polymorphic_impl(...); -template -struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic : public integral_constant(0)) == 1> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic + : public integral_constant(0)) == 1> + { + }; #endif // __WI_HAS_FEATURE_IS_POLYMORPHIC #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_polymorphic_v = is_polymorphic<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_polymorphic_v = is_polymorphic<_Tp>::value; #endif -// has_virtual_destructor + // has_virtual_destructor #if __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor + : public integral_constant + { + }; #else -template -struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor : public false_type + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_virtual_destructor_v = has_virtual_destructor<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_virtual_destructor_v = has_virtual_destructor<_Tp>::value; #endif -// has_unique_object_representations + // has_unique_object_representations #if __WI_LIBCPP_STD_VER > 14 && defined(__WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS) -template -struct __WI_LIBCPP_TEMPLATE_VIS has_unique_object_representations - : public integral_constant>)> -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_unique_object_representations_v = has_unique_object_representations<_Tp>::value; -#endif - -#endif - -// alignment_of - -template -struct __WI_LIBCPP_TEMPLATE_VIS alignment_of : public integral_constant -{ -}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t alignment_of_v = alignment_of<_Tp>::value; -#endif - -// aligned_storage - -template -struct __type_list -{ - typedef _Hp _Head; - typedef _Tp _Tail; -}; - -struct __nat -{ -#ifndef __WI_LIBCPP_CXX03_LANG - __nat() = delete; - __nat(const __nat&) = delete; - __nat& operator=(const __nat&) = delete; - ~__nat() = delete; -#endif -}; - -template -struct __align_type -{ - static const size_t value = alignment_of<_Tp>::value; - typedef _Tp type; -}; - -struct __struct_double -{ - long double __lx; -}; -struct __struct_double4 -{ - double __lx[4]; -}; - -typedef __type_list< - __align_type, - __type_list< - __align_type, - __type_list< - __align_type, - __type_list< - __align_type, - __type_list< - __align_type, - __type_list<__align_type, __type_list<__align_type, __type_list<__align_type<__struct_double>, __type_list<__align_type<__struct_double4>, __type_list<__align_type, __nat>>>>>>>>>> - __all_types; - -template -struct __find_pod; - -template -struct __find_pod<__type_list<_Hp, __nat>, _Align> -{ - typedef typename conditional<_Align == _Hp::value, typename _Hp::type, void>::type type; -}; - -template -struct __find_pod<__type_list<_Hp, _Tp>, _Align> -{ - typedef typename conditional<_Align == _Hp::value, typename _Hp::type, typename __find_pod<_Tp, _Align>::type>::type type; -}; - -template -struct __has_pod_with_align : public integral_constant::type, void>::value> -{ -}; - -template -struct __find_max_align; - -template -struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant -{ -}; - -template -struct __select_align -{ -private: - static const size_t __min = _A2 < _A1 ? _A2 : _A1; - static const size_t __max = _A1 < _A2 ? _A2 : _A1; - -public: - static const size_t value = _Len < __max ? __min : __max; -}; - -template -struct __find_max_align<__type_list<_Hp, _Tp>, _Len> - : public integral_constant::value>::value> -{ -}; - -template ::value> -struct __aligned_storage -{ - typedef typename __find_pod<__all_types, _Align>::type _Aligner; - static_assert(!is_void<_Aligner>::value, ""); - union type + template + struct __WI_LIBCPP_TEMPLATE_VIS has_unique_object_representations + : public integral_constant>)> { - _Aligner __align; - unsigned char __data[(_Len + _Align - 1) / _Align * _Align]; }; -}; -#define __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \ - template \ - struct __aligned_storage<_Len, n, false> \ - { \ - struct __WI_ALIGNAS(n) type \ - { \ - unsigned char __lx[(_Len + n - 1) / n * n]; \ - }; \ +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_unique_object_representations_v = + has_unique_object_representations<_Tp>::value; +#endif + +#endif + + // alignment_of + + template + struct __WI_LIBCPP_TEMPLATE_VIS alignment_of : public integral_constant + { + }; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t alignment_of_v = alignment_of<_Tp>::value; +#endif + + // aligned_storage + + template struct __type_list + { + typedef _Hp _Head; + typedef _Tp _Tail; + }; + + struct __nat + { +#ifndef __WI_LIBCPP_CXX03_LANG + __nat() = delete; + __nat(const __nat &) = delete; + __nat &operator=(const __nat &) = delete; + ~__nat() = delete; +#endif + }; + + template struct __align_type + { + static const size_t value = alignment_of<_Tp>::value; + typedef _Tp type; + }; + + struct __struct_double + { + long double __lx; + }; + struct __struct_double4 + { + double __lx[4]; + }; + + typedef __type_list< + __align_type, + __type_list< + __align_type, + __type_list< + __align_type, + __type_list< + __align_type, + __type_list< + __align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type<__struct_double>, + __type_list<__align_type<__struct_double4>, + __type_list<__align_type, __nat>>>>>>>>>> + __all_types; + + template struct __find_pod; + + template struct __find_pod<__type_list<_Hp, __nat>, _Align> + { + typedef typename conditional<_Align == _Hp::value, typename _Hp::type, void>::type type; + }; + + template struct __find_pod<__type_list<_Hp, _Tp>, _Align> + { + typedef + typename conditional<_Align == _Hp::value, typename _Hp::type, typename __find_pod<_Tp, _Align>::type>::type + type; + }; + + template + struct __has_pod_with_align + : public integral_constant::type, void>::value> + { + }; + + template struct __find_max_align; + + template + struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant + { + }; + + template struct __select_align + { + private: + static const size_t __min = _A2 < _A1 ? _A2 : _A1; + static const size_t __max = _A1 < _A2 ? _A2 : _A1; + + public: + static const size_t value = _Len < __max ? __min : __max; + }; + + template + struct __find_max_align<__type_list<_Hp, _Tp>, _Len> + : public integral_constant::value>::value> + { + }; + + template ::value> struct __aligned_storage + { + typedef typename __find_pod<__all_types, _Align>::type _Aligner; + static_assert(!is_void<_Aligner>::value, ""); + union type { + _Aligner __align; + unsigned char __data[(_Len + _Align - 1) / _Align * _Align]; + }; + }; + +#define __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \ + template struct __aligned_storage<_Len, n, false> \ + { \ + struct __WI_ALIGNAS(n) type \ + { \ + unsigned char __lx[(_Len + n - 1) / n * n]; \ + }; \ } -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000); -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000); // PE/COFF does not support alignment beyond 8192 (=0x2000) #if !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) -__WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000); #endif // !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) #undef __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION -template ::value> -struct __WI_LIBCPP_TEMPLATE_VIS aligned_storage : public __aligned_storage<_Len, _Align> -{ -}; + template ::value> + struct __WI_LIBCPP_TEMPLATE_VIS aligned_storage : public __aligned_storage<_Len, _Align> + { + }; #if __WI_LIBCPP_STD_VER > 11 -template ::value> -using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; + template ::value> + using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; #endif #ifndef __WI_LIBCPP_HAS_NO_VARIADICS -// aligned_union + // aligned_union -template -struct __static_max; + template struct __static_max; -template -struct __static_max<_I0> -{ - static const size_t value = _I0; -}; + template struct __static_max<_I0> + { + static const size_t value = _I0; + }; -template -struct __static_max<_I0, _I1, _In...> -{ - static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value : __static_max<_I1, _In...>::value; -}; + template struct __static_max<_I0, _I1, _In...> + { + static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value : __static_max<_I1, _In...>::value; + }; -template -struct aligned_union -{ - static const size_t alignment_value = __static_max<__alignof__(_Type0), __alignof__(_Types)...>::value; - static const size_t __len = __static_max<_Len, sizeof(_Type0), sizeof(_Types)...>::value; - typedef typename aligned_storage<__len, alignment_value>::type type; -}; + template struct aligned_union + { + static const size_t alignment_value = __static_max<__alignof__(_Type0), __alignof__(_Types)...>::value; + static const size_t __len = __static_max<_Len, sizeof(_Type0), sizeof(_Types)...>::value; + typedef typename aligned_storage<__len, alignment_value>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using aligned_union_t = typename aligned_union<_Len, _Types...>::type; + template using aligned_union_t = typename aligned_union<_Len, _Types...>::type; #endif #endif // __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __numeric_type -{ - static void __test(...); - static float __test(float); - static double __test(char); - static double __test(int); - static double __test(unsigned); - static double __test(long); - static double __test(unsigned long); - static double __test(long long); - static double __test(unsigned long long); - static double __test(double); - static long double __test(long double); + template struct __numeric_type + { + static void __test(...); + static float __test(float); + static double __test(char); + static double __test(int); + static double __test(unsigned); + static double __test(long); + static double __test(unsigned long); + static double __test(long long); + static double __test(unsigned long long); + static double __test(double); + static long double __test(long double); - typedef decltype(__test(declval<_Tp>())) type; - static const bool value = !is_same::value; -}; + typedef decltype(__test(declval<_Tp>())) type; + static const bool value = !is_same::value; + }; -template <> -struct __numeric_type -{ - static const bool value = true; -}; + template <> struct __numeric_type + { + static const bool value = true; + }; -// __promote + // __promote -template ::value && __numeric_type<_A2>::value && __numeric_type<_A3>::value> -class __promote_imp -{ -public: - static const bool value = false; -}; + template ::value && __numeric_type<_A2>::value && __numeric_type<_A3>::value> + class __promote_imp + { + public: + static const bool value = false; + }; -template -class __promote_imp<_A1, _A2, _A3, true> -{ -private: - typedef typename __promote_imp<_A1>::type __type1; - typedef typename __promote_imp<_A2>::type __type2; - typedef typename __promote_imp<_A3>::type __type3; + template class __promote_imp<_A1, _A2, _A3, true> + { + private: + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2; + typedef typename __promote_imp<_A3>::type __type3; -public: - typedef decltype(__type1() + __type2() + __type3()) type; - static const bool value = true; -}; + public: + typedef decltype(__type1() + __type2() + __type3()) type; + static const bool value = true; + }; -template -class __promote_imp<_A1, _A2, void, true> -{ -private: - typedef typename __promote_imp<_A1>::type __type1; - typedef typename __promote_imp<_A2>::type __type2; + template class __promote_imp<_A1, _A2, void, true> + { + private: + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2; -public: - typedef decltype(__type1() + __type2()) type; - static const bool value = true; -}; + public: + typedef decltype(__type1() + __type2()) type; + static const bool value = true; + }; -template -class __promote_imp<_A1, void, void, true> -{ -public: - typedef typename __numeric_type<_A1>::type type; - static const bool value = true; -}; + template class __promote_imp<_A1, void, void, true> + { + public: + typedef typename __numeric_type<_A1>::type type; + static const bool value = true; + }; -template -class __promote : public __promote_imp<_A1, _A2, _A3> -{ -}; + template class __promote : public __promote_imp<_A1, _A2, _A3> + { + }; -// make_signed / make_unsigned + // make_signed / make_unsigned -typedef __type_list< - signed char, - __type_list< - signed short, - __type_list< - signed int, - __type_list< - signed long, - __type_list< - signed long long, + typedef __type_list< + signed char, + __type_list + > #endif - >>>>> - __signed_types; + >>>>> + __signed_types; -typedef __type_list< - unsigned char, - __type_list< - unsigned short, - __type_list< - unsigned int, - __type_list< - unsigned long, - __type_list< - unsigned long long, + typedef __type_list< + unsigned char, + __type_list + > #endif - >>>>> - __unsigned_types; + >>>>> + __unsigned_types; -template -struct __find_first; + template struct __find_first; -template -struct __find_first<__type_list<_Hp, _Tp>, _Size, true> -{ - typedef _Hp type; -}; + template struct __find_first<__type_list<_Hp, _Tp>, _Size, true> + { + typedef _Hp type; + }; -template -struct __find_first<__type_list<_Hp, _Tp>, _Size, false> -{ - typedef typename __find_first<_Tp, _Size>::type type; -}; + template struct __find_first<__type_list<_Hp, _Tp>, _Size, false> + { + typedef typename __find_first<_Tp, _Size>::type type; + }; -template ::type>::value, bool = is_volatile::type>::value> -struct __apply_cv -{ - typedef _Up type; -}; + template ::type>::value, + bool = is_volatile::type>::value> + struct __apply_cv + { + typedef _Up type; + }; -template -struct __apply_cv<_Tp, _Up, true, false> -{ - typedef const _Up type; -}; + template struct __apply_cv<_Tp, _Up, true, false> + { + typedef const _Up type; + }; -template -struct __apply_cv<_Tp, _Up, false, true> -{ - typedef volatile _Up type; -}; + template struct __apply_cv<_Tp, _Up, false, true> + { + typedef volatile _Up type; + }; -template -struct __apply_cv<_Tp, _Up, true, true> -{ - typedef const volatile _Up type; -}; + template struct __apply_cv<_Tp, _Up, true, true> + { + typedef const volatile _Up type; + }; -template -struct __apply_cv<_Tp&, _Up, false, false> -{ - typedef _Up& type; -}; + template struct __apply_cv<_Tp &, _Up, false, false> + { + typedef _Up &type; + }; -template -struct __apply_cv<_Tp&, _Up, true, false> -{ - typedef const _Up& type; -}; + template struct __apply_cv<_Tp &, _Up, true, false> + { + typedef const _Up &type; + }; -template -struct __apply_cv<_Tp&, _Up, false, true> -{ - typedef volatile _Up& type; -}; + template struct __apply_cv<_Tp &, _Up, false, true> + { + typedef volatile _Up &type; + }; -template -struct __apply_cv<_Tp&, _Up, true, true> -{ - typedef const volatile _Up& type; -}; + template struct __apply_cv<_Tp &, _Up, true, true> + { + typedef const volatile _Up &type; + }; -template ::value || is_enum<_Tp>::value> -struct __make_signed{}; + template ::value || is_enum<_Tp>::value> struct __make_signed{}; -template -struct __make_signed<_Tp, true> -{ - typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type; -}; + template struct __make_signed<_Tp, true> + { + typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type; + }; -template <> -struct __make_signed{}; -template <> -struct __make_signed -{ - typedef short type; -}; -template <> -struct __make_signed -{ - typedef short type; -}; -template <> -struct __make_signed -{ - typedef int type; -}; -template <> -struct __make_signed -{ - typedef int type; -}; -template <> -struct __make_signed -{ - typedef long type; -}; -template <> -struct __make_signed -{ - typedef long type; -}; -template <> -struct __make_signed -{ - typedef long long type; -}; -template <> -struct __make_signed -{ - typedef long long type; -}; + template <> struct __make_signed{}; + template <> struct __make_signed + { + typedef short type; + }; + template <> struct __make_signed + { + typedef short type; + }; + template <> struct __make_signed + { + typedef int type; + }; + template <> struct __make_signed + { + typedef int type; + }; + template <> struct __make_signed + { + typedef long type; + }; + template <> struct __make_signed + { + typedef long type; + }; + template <> struct __make_signed + { + typedef long long type; + }; + template <> struct __make_signed + { + typedef long long type; + }; #ifndef __WI_LIBCPP_HAS_NO_INT128 -template <> -struct __make_signed<__int128_t, true> -{ - typedef __int128_t type; -}; -template <> -struct __make_signed<__uint128_t, true> -{ - typedef __int128_t type; -}; + template <> struct __make_signed<__int128_t, true> + { + typedef __int128_t type; + }; + template <> struct __make_signed<__uint128_t, true> + { + typedef __int128_t type; + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS make_signed -{ - typedef typename __apply_cv<_Tp, typename __make_signed::type>::type>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS make_signed + { + typedef typename __apply_cv<_Tp, typename __make_signed::type>::type>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using make_signed_t = typename make_signed<_Tp>::type; + template using make_signed_t = typename make_signed<_Tp>::type; #endif -template ::value || is_enum<_Tp>::value> -struct __make_unsigned{}; + template ::value || is_enum<_Tp>::value> struct __make_unsigned{}; -template -struct __make_unsigned<_Tp, true> -{ - typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type; -}; + template struct __make_unsigned<_Tp, true> + { + typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type; + }; -template <> -struct __make_unsigned{}; -template <> -struct __make_unsigned -{ - typedef unsigned short type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned short type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned int type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned int type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned long type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned long type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned long long type; -}; -template <> -struct __make_unsigned -{ - typedef unsigned long long type; -}; + template <> struct __make_unsigned{}; + template <> struct __make_unsigned + { + typedef unsigned short type; + }; + template <> struct __make_unsigned + { + typedef unsigned short type; + }; + template <> struct __make_unsigned + { + typedef unsigned int type; + }; + template <> struct __make_unsigned + { + typedef unsigned int type; + }; + template <> struct __make_unsigned + { + typedef unsigned long type; + }; + template <> struct __make_unsigned + { + typedef unsigned long type; + }; + template <> struct __make_unsigned + { + typedef unsigned long long type; + }; + template <> struct __make_unsigned + { + typedef unsigned long long type; + }; #ifndef __WI_LIBCPP_HAS_NO_INT128 -template <> -struct __make_unsigned<__int128_t, true> -{ - typedef __uint128_t type; -}; -template <> -struct __make_unsigned<__uint128_t, true> -{ - typedef __uint128_t type; -}; + template <> struct __make_unsigned<__int128_t, true> + { + typedef __uint128_t type; + }; + template <> struct __make_unsigned<__uint128_t, true> + { + typedef __uint128_t type; + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS make_unsigned -{ - typedef typename __apply_cv<_Tp, typename __make_unsigned::type>::type>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS make_unsigned + { + typedef typename __apply_cv<_Tp, typename __make_unsigned::type>::type>::type type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using make_unsigned_t = typename make_unsigned<_Tp>::type; + template using make_unsigned_t = typename make_unsigned<_Tp>::type; #endif #ifdef __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type -{ -public: - typedef typename common_type::type, _Vp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type + { + public: + typedef typename common_type::type, _Vp>::type type; + }; -template <> -struct __WI_LIBCPP_TEMPLATE_VIS common_type -{ -public: - typedef void type; -}; + template <> struct __WI_LIBCPP_TEMPLATE_VIS common_type + { + public: + typedef void type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, void, void> -{ -public: - typedef typename common_type<_Tp, _Tp>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, void, void> + { + public: + typedef typename common_type<_Tp, _Tp>::type type; + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, void> -{ - typedef typename decay() : declval<_Up>())>::type type; -}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, void> + { + typedef typename decay() : declval<_Up>())>::type type; + }; #else // __WI_LIBCPP_HAS_NO_VARIADICS -// bullet 1 - sizeof...(Tp) == 0 + // bullet 1 - sizeof...(Tp) == 0 -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type{}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type{}; -// bullet 2 - sizeof...(Tp) == 1 + // bullet 2 - sizeof...(Tp) == 1 -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp> : public common_type<_Tp, _Tp> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp> : public common_type<_Tp, _Tp> + { + }; -// bullet 3 - sizeof...(Tp) == 2 + // bullet 3 - sizeof...(Tp) == 2 -template -struct __common_type2_imp -{ -}; + template struct __common_type2_imp + { + }; -template -struct __common_type2_imp<_Tp, _Up, typename __void_t() : declval<_Up>())>::type> -{ - typedef typename decay() : declval<_Up>())>::type type; -}; + template + struct __common_type2_imp<_Tp, _Up, typename __void_t() : declval<_Up>())>::type> + { + typedef typename decay() : declval<_Up>())>::type type; + }; -template ::type, class _DUp = typename decay<_Up>::type> -using __common_type2 = - typename conditional::value && is_same<_Up, _DUp>::value, __common_type2_imp<_Tp, _Up>, common_type<_DTp, _DUp>>::type; + template ::type, class _DUp = typename decay<_Up>::type> + using __common_type2 = typename conditional::value && is_same<_Up, _DUp>::value, + __common_type2_imp<_Tp, _Up>, common_type<_DTp, _DUp>>::type; -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> : __common_type2<_Tp, _Up> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> : __common_type2<_Tp, _Up> + { + }; -// bullet 4 - sizeof...(Tp) > 2 + // bullet 4 - sizeof...(Tp) > 2 -template -struct __common_types; + template struct __common_types; -template -struct __common_type_impl -{ -}; + template struct __common_type_impl + { + }; -template -struct __common_type_impl<__common_types<_Tp, _Up>, typename __void_t::type>::type> -{ - typedef typename common_type<_Tp, _Up>::type type; -}; + template + struct __common_type_impl<__common_types<_Tp, _Up>, typename __void_t::type>::type> + { + typedef typename common_type<_Tp, _Up>::type type; + }; -template -struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>, typename __void_t::type>::type> - : __common_type_impl<__common_types::type, _Vp...>> -{ -}; + template + struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>, + typename __void_t::type>::type> + : __common_type_impl<__common_types::type, _Vp...>> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, _Vp...> : __common_type_impl<__common_types<_Tp, _Up, _Vp...>> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, _Vp...> : __common_type_impl<__common_types<_Tp, _Up, _Vp...>> + { + }; #if __WI_LIBCPP_STD_VER > 11 -template -using common_type_t = typename common_type<_Tp...>::type; + template using common_type_t = typename common_type<_Tp...>::type; #endif #endif // __WI_LIBCPP_HAS_NO_VARIADICS -// is_assignable + // is_assignable -template -struct __select_2nd -{ - typedef _Tp type; -}; + template struct __select_2nd + { + typedef _Tp type; + }; -template -typename __select_2nd() = declval<_Arg>())), true_type>::type __is_assignable_test(int); + template + typename __select_2nd() = declval<_Arg>())), true_type>::type __is_assignable_test(int); -template -false_type __is_assignable_test(...); + template false_type __is_assignable_test(...); -template ::value || is_void<_Arg>::value> -struct __is_assignable_imp : public decltype((__is_assignable_test<_Tp, _Arg>(0))) -{ -}; + template ::value || is_void<_Arg>::value> + struct __is_assignable_imp : public decltype((__is_assignable_test<_Tp, _Arg>(0))) + { + }; -template -struct __is_assignable_imp<_Tp, _Arg, true> : public false_type -{ -}; + template struct __is_assignable_imp<_Tp, _Arg, true> : public false_type + { + }; -template -struct is_assignable : public __is_assignable_imp<_Tp, _Arg> -{ -}; + template struct is_assignable : public __is_assignable_imp<_Tp, _Arg> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_assignable_v = is_assignable<_Tp, _Arg>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_assignable_v = is_assignable<_Tp, _Arg>::value; #endif -// is_copy_assignable + // is_copy_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_copy_assignable - : public is_assignable::type, typename add_lvalue_reference::type>::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_copy_assignable + : public is_assignable::type, + typename add_lvalue_reference::type>::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_assignable_v = is_copy_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_assignable_v = is_copy_assignable<_Tp>::value; #endif -// is_move_assignable + // is_move_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_move_assignable + template + struct __WI_LIBCPP_TEMPLATE_VIS is_move_assignable #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_assignable::type, typename add_rvalue_reference<_Tp>::type> -{ -}; + : public is_assignable::type, typename add_rvalue_reference<_Tp>::type> + { + }; #else - : public is_copy_assignable<_Tp> -{ -}; + : public is_copy_assignable<_Tp> + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_assignable_v = is_move_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_assignable_v = is_move_assignable<_Tp>::value; #endif -// is_destructible + // is_destructible #if __WI_HAS_FEATURE_IS_DESTRUCTIBLE -template -struct is_destructible : public integral_constant -{ -}; + template struct is_destructible : public integral_constant + { + }; #else -// if it's a reference, return true -// if it's a function, return false -// if it's void, return false -// if it's an array of unknown bound, return false -// Otherwise, return "std::declval<_Up&>().~_Up()" is well-formed -// where _Up is remove_all_extents<_Tp>::type + // if it's a reference, return true + // if it's a function, return false + // if it's void, return false + // if it's an array of unknown bound, return false + // Otherwise, return "std::declval<_Up&>().~_Up()" is well-formed + // where _Up is remove_all_extents<_Tp>::type -template -struct __is_destructible_apply -{ - typedef int type; -}; + template struct __is_destructible_apply + { + typedef int type; + }; -template -struct __is_destructor_wellformed -{ - template - static char __test(typename __is_destructible_apply().~_Tp1())>::type); + template struct __is_destructor_wellformed + { + template + static char __test(typename __is_destructible_apply().~_Tp1())>::type); - template - static __two __test(...); + template static __two __test(...); - static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char); -}; + static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char); + }; -template -struct __destructible_imp; + template struct __destructible_imp; -template -struct __destructible_imp<_Tp, false> - : public integral_constant::type>::value> -{ -}; + template + struct __destructible_imp<_Tp, false> + : public integral_constant::type>::value> + { + }; -template -struct __destructible_imp<_Tp, true> : public true_type -{ -}; + template struct __destructible_imp<_Tp, true> : public true_type + { + }; -template -struct __destructible_false; + template struct __destructible_false; -template -struct __destructible_false<_Tp, false> : public __destructible_imp<_Tp, is_reference<_Tp>::value> -{ -}; + template + struct __destructible_false<_Tp, false> : public __destructible_imp<_Tp, is_reference<_Tp>::value> + { + }; -template -struct __destructible_false<_Tp, true> : public false_type -{ -}; + template struct __destructible_false<_Tp, true> : public false_type + { + }; -template -struct is_destructible : public __destructible_false<_Tp, is_function<_Tp>::value> -{ -}; + template struct is_destructible : public __destructible_false<_Tp, is_function<_Tp>::value> + { + }; -template -struct is_destructible<_Tp[]> : public false_type -{ -}; + template struct is_destructible<_Tp[]> : public false_type + { + }; -template <> -struct is_destructible : public false_type -{ -}; + template <> struct is_destructible : public false_type + { + }; #endif // __WI_HAS_FEATURE_IS_DESTRUCTIBLE #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_destructible_v = is_destructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_destructible_v = is_destructible<_Tp>::value; #endif -// move + // move #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR typename remove_reference<_Tp>::type&& move(_Tp&& __t) WI_NOEXCEPT -{ - typedef typename remove_reference<_Tp>::type _Up; - return static_cast<_Up&&>(__t); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR typename remove_reference<_Tp>::type &&move(_Tp &&__t) + WI_NOEXCEPT + { + typedef typename remove_reference<_Tp>::type _Up; + return static_cast<_Up &&>(__t); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR _Tp&& forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT -{ - return static_cast<_Tp&&>(__t); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR _Tp &&forward(typename remove_reference<_Tp>::type &__t) + WI_NOEXCEPT + { + return static_cast<_Tp &&>(__t); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR _Tp&& forward(typename remove_reference<_Tp>::type&& __t) WI_NOEXCEPT -{ - static_assert(!is_lvalue_reference<_Tp>::value, "can not forward an rvalue as an lvalue"); - return static_cast<_Tp&&>(__t); -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR _Tp &&forward(typename remove_reference<_Tp>::type &&__t) + WI_NOEXCEPT + { + static_assert(!is_lvalue_reference<_Tp>::value, "can not forward an rvalue as an lvalue"); + return static_cast<_Tp &&>(__t); + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 _T1 exchange(_T1& __obj, _T2&& __new_value) -{ - _T1 __old_value = wistd::move(__obj); - __obj = wistd::forward<_T2>(__new_value); - return __old_value; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 _T1 exchange(_T1 &__obj, _T2 &&__new_value) + { + _T1 __old_value = wistd::move(__obj); + __obj = wistd::forward<_T2>(__new_value); + return __old_value; + } #else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -inline __WI_LIBCPP_INLINE_VISIBILITY _Tp& move(_Tp& __t) -{ - return __t; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY const _Tp& move(const _Tp& __t) -{ - return __t; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY _Tp& forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT -{ - return __t; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY _T1 exchange(_T1& __obj, const _T2& __new_value) -{ - _T1 __old_value = __obj; - __obj = __new_value; - return __old_value; -} - -template -class __rv -{ - typedef typename remove_reference<_Tp>::type _Trr; - _Trr& t_; - -public: - __WI_LIBCPP_INLINE_VISIBILITY - _Trr* operator->() + template inline __WI_LIBCPP_INLINE_VISIBILITY _Tp &move(_Tp &__t) { - return &t_; + return __t; } - __WI_LIBCPP_INLINE_VISIBILITY - explicit __rv(_Trr& __t) : t_(__t) + + template inline __WI_LIBCPP_INLINE_VISIBILITY const _Tp &move(const _Tp &__t) { + return __t; } -}; + + template + inline __WI_LIBCPP_INLINE_VISIBILITY _Tp &forward(typename remove_reference<_Tp>::type &__t) WI_NOEXCEPT + { + return __t; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY _T1 exchange(_T1 &__obj, const _T2 &__new_value) + { + _T1 __old_value = __obj; + __obj = __new_value; + return __old_value; + } + + template class __rv + { + typedef typename remove_reference<_Tp>::type _Trr; + _Trr &t_; + + public: + __WI_LIBCPP_INLINE_VISIBILITY + _Trr *operator->() + { + return &t_; + } + __WI_LIBCPP_INLINE_VISIBILITY + explicit __rv(_Trr &__t) : t_(__t) + { + } + }; #endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES #if __WI_LIBCPP_STD_VER > 11 -template + template #else -template + template #endif -struct __WI_LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool> -{ - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY bool operator()( - const _Tp& __x, const _Tp& __y) const + struct __WI_LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool> { - return __x < __y; - } -}; + __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY bool operator()( + const _Tp &__x, const _Tp &__y) const + { + return __x < __y; + } + }; #if __WI_LIBCPP_STD_VER > 11 -template <> -struct __WI_LIBCPP_TEMPLATE_VIS less -{ - template - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY auto operator()(_T1&& __t, _T2&& __u) const - __WI_NOEXCEPT_(noexcept(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u))) - -> decltype(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u)) + template <> struct __WI_LIBCPP_TEMPLATE_VIS less { - return wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u); - } - typedef void is_transparent; -}; + template + __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY auto operator()( + _T1 &&__t, _T2 &&__u) const __WI_NOEXCEPT_(noexcept(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u))) + -> decltype(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u)) + { + return wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u); + } + typedef void is_transparent; + }; #endif #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -inline __WI_LIBCPP_INLINE_VISIBILITY typename decay<_Tp>::type __decay_copy(_Tp&& __t) -{ - return wistd::forward<_Tp>(__t); -} + template inline __WI_LIBCPP_INLINE_VISIBILITY typename decay<_Tp>::type __decay_copy(_Tp &&__t) + { + return wistd::forward<_Tp>(__t); + } #else -template -inline __WI_LIBCPP_INLINE_VISIBILITY typename decay<_Tp>::type __decay_copy(const _Tp& __t) -{ - return wistd::forward<_Tp>(__t); -} + template inline __WI_LIBCPP_INLINE_VISIBILITY typename decay<_Tp>::type __decay_copy(const _Tp &__t) + { + return wistd::forward<_Tp>(__t); + } #endif #ifndef __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; #if __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || (defined(__WI_GNUC_VER) && __WI_GNUC_VER >= 409) -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...)&, true, false> -{ - typedef _Class& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &, true, false> + { + typedef _Class &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...)&, true, false> -{ - typedef _Class& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &, true, false> + { + typedef _Class &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&, true, false> -{ - typedef _Class const& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const &, true, false> + { + typedef _Class const &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&, true, false> -{ - typedef _Class const& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const &, true, false> + { + typedef _Class const &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&, true, false> -{ - typedef _Class volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile &, true, false> + { + typedef _Class volatile &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&, true, false> -{ - typedef _Class volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile &, true, false> + { + typedef _Class volatile &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&, true, false> -{ - typedef _Class const volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile &, true, false> + { + typedef _Class const volatile &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&, true, false> -{ - typedef _Class const volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile &, true, false> + { + typedef _Class const volatile &_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...)&&, true, false> -{ - typedef _Class&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &&, true, false> + { + typedef _Class &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...)&&, true, false> -{ - typedef _Class&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &&, true, false> + { + typedef _Class &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&&, true, false> -{ - typedef _Class const&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const &&, true, false> + { + typedef _Class const &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&&, true, false> -{ - typedef _Class const&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const &&, true, false> + { + typedef _Class const &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&&, true, false> -{ - typedef _Class volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile &&, true, false> + { + typedef _Class volatile &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&&, true, false> -{ - typedef _Class volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile &&, true, false> + { + typedef _Class volatile &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&&, true, false> -{ - typedef _Class const volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile &&, true, false> + { + typedef _Class const volatile &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&&, true, false> -{ - typedef _Class const volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_Param..., ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile &&, true, false> + { + typedef _Class const volatile &&_ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_Param..., ...); + }; #endif // __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || __WI_GNUC_VER >= 409 #else // __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)(), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(...); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)(...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...), true, false> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)() const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)() const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(...); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const, true, false> -{ - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)() volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)() volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(...); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)(...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) volatile, true, false> -{ - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)() const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(); -}; + template struct __member_pointer_traits_imp<_Rp (_Class::*)() const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, ...); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2); + }; -template -struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const volatile, true, false> -{ - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp(_FnType)(_P0, _P1, _P2, ...); -}; + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp(_FnType)(_P0, _P1, _P2, ...); + }; #endif // __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __member_pointer_traits_imp<_Rp _Class::*, false, true> -{ - typedef _Class _ClassType; - typedef _Rp _ReturnType; -}; + template struct __member_pointer_traits_imp<_Rp _Class::*, false, true> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + }; -template -struct __member_pointer_traits - : public __member_pointer_traits_imp::type, is_member_function_pointer<_Mp>::value, is_member_object_pointer<_Mp>::value> -{ - // typedef ... _ClassType; - // typedef ... _ReturnType; - // typedef ... _FnType; -}; + template + struct __member_pointer_traits + : public __member_pointer_traits_imp::type, is_member_function_pointer<_Mp>::value, + is_member_object_pointer<_Mp>::value> + { + // typedef ... _ClassType; + // typedef ... _ReturnType; + // typedef ... _FnType; + }; -template -struct __member_pointer_class_type -{ -}; + template struct __member_pointer_class_type + { + }; -template -struct __member_pointer_class_type<_Ret _ClassType::*> -{ - typedef _ClassType type; -}; + template struct __member_pointer_class_type<_Ret _ClassType::*> + { + typedef _ClassType type; + }; -// result_of + // result_of -template -class result_of; + template class result_of; #ifdef __WI_LIBCPP_HAS_NO_VARIADICS -template -class __result_of -{ -}; + template class __result_of + { + }; -template -class __result_of<_Fn(), true, false> -{ -public: - typedef decltype(declval<_Fn>()()) type; -}; + template class __result_of<_Fn(), true, false> + { + public: + typedef decltype(declval<_Fn>()()) type; + }; -template -class __result_of<_Fn(_A0), true, false> -{ -public: - typedef decltype(declval<_Fn>()(declval<_A0>())) type; -}; + template class __result_of<_Fn(_A0), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>())) type; + }; -template -class __result_of<_Fn(_A0, _A1), true, false> -{ -public: - typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>())) type; -}; + template class __result_of<_Fn(_A0, _A1), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>())) type; + }; -template -class __result_of<_Fn(_A0, _A1, _A2), true, false> -{ -public: - typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>(), declval<_A2>())) type; -}; + template class __result_of<_Fn(_A0, _A1, _A2), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>(), declval<_A2>())) type; + }; -template -struct __result_of_mp; + template struct __result_of_mp; -// member function pointer + // member function pointer -template -struct __result_of_mp<_Mp, _Tp, true> : public __identity::_ReturnType> -{ -}; + template + struct __result_of_mp<_Mp, _Tp, true> : public __identity::_ReturnType> + { + }; -// member data pointer + // member data pointer -template -struct __result_of_mdp; + template struct __result_of_mdp; -template -struct __result_of_mdp<_Rp _Class::*, _Tp, false> -{ - typedef typename __apply_cv()), _Rp>::type& type; -}; + template struct __result_of_mdp<_Rp _Class::*, _Tp, false> + { + typedef typename __apply_cv()), _Rp>::type &type; + }; -template -struct __result_of_mdp<_Rp _Class::*, _Tp, true> -{ - typedef typename __apply_cv<_Tp, _Rp>::type& type; -}; + template struct __result_of_mdp<_Rp _Class::*, _Tp, true> + { + typedef typename __apply_cv<_Tp, _Rp>::type &type; + }; -template -struct __result_of_mp<_Rp _Class::*, _Tp, false> - : public __result_of_mdp<_Rp _Class::*, _Tp, is_base_of<_Class, typename remove_reference<_Tp>::type>::value> -{ -}; + template + struct __result_of_mp<_Rp _Class::*, _Tp, false> + : public __result_of_mdp<_Rp _Class::*, _Tp, is_base_of<_Class, typename remove_reference<_Tp>::type>::value> + { + }; -template -class __result_of<_Fn(_Tp), false, true> // _Fn must be member pointer - : public __result_of_mp::type, _Tp, is_member_function_pointer::type>::value> -{ -}; + template + class __result_of<_Fn(_Tp), false, true> // _Fn must be member pointer + : public __result_of_mp::type, _Tp, + is_member_function_pointer::type>::value> + { + }; -template -class __result_of<_Fn(_Tp, _A0), false, true> // _Fn must be member pointer - : public __result_of_mp::type, _Tp, is_member_function_pointer::type>::value> -{ -}; + template + class __result_of<_Fn(_Tp, _A0), false, true> // _Fn must be member pointer + : public __result_of_mp::type, _Tp, + is_member_function_pointer::type>::value> + { + }; -template -class __result_of<_Fn(_Tp, _A0, _A1), false, true> // _Fn must be member pointer - : public __result_of_mp::type, _Tp, is_member_function_pointer::type>::value> -{ -}; + template + class __result_of<_Fn(_Tp, _A0, _A1), false, true> // _Fn must be member pointer + : public __result_of_mp::type, _Tp, + is_member_function_pointer::type>::value> + { + }; -template -class __result_of<_Fn(_Tp, _A0, _A1, _A2), false, true> // _Fn must be member pointer - : public __result_of_mp::type, _Tp, is_member_function_pointer::type>::value> -{ -}; + template + class __result_of<_Fn(_Tp, _A0, _A1, _A2), false, true> // _Fn must be member pointer + : public __result_of_mp::type, _Tp, + is_member_function_pointer::type>::value> + { + }; -// result_of + // result_of -template -class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn()> - : public __result_of< - _Fn(), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value> -{ -}; + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn()> + : public __result_of< + _Fn(), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value> + { + }; -template -class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0)> - : public __result_of< - _Fn(_A0), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value> -{ -}; + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0)> + : public __result_of< + _Fn(_A0), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value> + { + }; -template -class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1)> - : public __result_of< - _Fn(_A0, _A1), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value> -{ -}; + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1)> + : public __result_of< + _Fn(_A0, _A1), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value> + { + }; -template -class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1, _A2)> - : public __result_of< - _Fn(_A0, _A1, _A2), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value> -{ -}; + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1, _A2)> + : public __result_of< + _Fn(_A0, _A1, _A2), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value> + { + }; #endif // __WI_LIBCPP_HAS_NO_VARIADICS -// template struct is_constructible; + // template struct is_constructible; -namespace __is_construct -{ - struct __nat + namespace __is_construct + { + struct __nat + { + }; + } // namespace __is_construct + +#if !defined(__WI_LIBCPP_CXX03_LANG) && \ + (!__WI_HAS_FEATURE_IS_CONSTRUCTIBLE || defined(__WI_LIBCPP_TESTING_FALLBACK_IS_CONSTRUCTIBLE)) + + template struct __libcpp_is_constructible; + + template struct __is_invalid_base_to_derived_cast + { + static_assert(is_reference<_To>::value, "Wrong specialization"); + using _RawFrom = __uncvref_t<_From>; + using _RawTo = __uncvref_t<_To>; + static const bool value = __lazy_and<__lazy_not>, is_base_of<_RawFrom, _RawTo>, + __lazy_not<__libcpp_is_constructible<_RawTo, _From>>>::value; + }; + + template struct __is_invalid_lvalue_to_rvalue_cast : false_type + { + static_assert(is_reference<_To>::value, "Wrong specialization"); + }; + + template struct __is_invalid_lvalue_to_rvalue_cast<_ToRef &&, _FromRef &> + { + using _RawFrom = __uncvref_t<_FromRef>; + using _RawTo = __uncvref_t<_ToRef>; + static const bool value = __lazy_and<__lazy_not>, + __lazy_or, is_base_of<_RawTo, _RawFrom>>>::value; + }; + + struct __is_constructible_helper + { + template static void __eat(_To); + + // This overload is needed to work around a Clang bug that disallows + // static_cast(e) for non-reference-compatible types. + // Example: static_cast(declval()); + // NOTE: The static_cast implementation below is required to support + // classes with explicit conversion operators. + template (declval<_From>()))> + static true_type __test_cast(int); + + template (declval<_From>()))> + static integral_constant::value && + !__is_invalid_lvalue_to_rvalue_cast<_To, _From>::value> + __test_cast(long); + + template static false_type __test_cast(...); + + template ()...))> + static true_type __test_nary(int); + template static false_type __test_nary(...); + + template ()))> + static is_destructible<_Tp> __test_unary(int); + template static false_type __test_unary(...); + }; + + template ::value> + struct __is_default_constructible : decltype(__is_constructible_helper::__test_nary<_Tp>(0)) { }; -} // namespace __is_construct -#if !defined(__WI_LIBCPP_CXX03_LANG) && (!__WI_HAS_FEATURE_IS_CONSTRUCTIBLE || defined(__WI_LIBCPP_TESTING_FALLBACK_IS_CONSTRUCTIBLE)) + template struct __is_default_constructible<_Tp, true> : false_type + { + }; -template -struct __libcpp_is_constructible; + template struct __is_default_constructible<_Tp[], false> : false_type + { + }; -template -struct __is_invalid_base_to_derived_cast -{ - static_assert(is_reference<_To>::value, "Wrong specialization"); - using _RawFrom = __uncvref_t<_From>; - using _RawTo = __uncvref_t<_To>; - static const bool value = - __lazy_and<__lazy_not>, is_base_of<_RawFrom, _RawTo>, __lazy_not<__libcpp_is_constructible<_RawTo, _From>>>::value; -}; + template + struct __is_default_constructible<_Tp[_Nx], false> + : __is_default_constructible::type> + { + }; -template -struct __is_invalid_lvalue_to_rvalue_cast : false_type -{ - static_assert(is_reference<_To>::value, "Wrong specialization"); -}; + template struct __libcpp_is_constructible + { + static_assert(sizeof...(_Args) > 1, "Wrong specialization"); + typedef decltype(__is_constructible_helper::__test_nary<_Tp, _Args...>(0)) type; + }; -template -struct __is_invalid_lvalue_to_rvalue_cast<_ToRef&&, _FromRef&> -{ - using _RawFrom = __uncvref_t<_FromRef>; - using _RawTo = __uncvref_t<_ToRef>; - static const bool value = - __lazy_and<__lazy_not>, __lazy_or, is_base_of<_RawTo, _RawFrom>>>::value; -}; + template struct __libcpp_is_constructible<_Tp> : __is_default_constructible<_Tp> + { + }; -struct __is_constructible_helper -{ - template - static void __eat(_To); + template + struct __libcpp_is_constructible<_Tp, _A0> : public decltype(__is_constructible_helper::__test_unary<_Tp, _A0>(0)) + { + }; - // This overload is needed to work around a Clang bug that disallows - // static_cast(e) for non-reference-compatible types. - // Example: static_cast(declval()); - // NOTE: The static_cast implementation below is required to support - // classes with explicit conversion operators. - template (declval<_From>()))> - static true_type __test_cast(int); + template + struct __libcpp_is_constructible<_Tp &, _A0> + : public decltype(__is_constructible_helper::__test_cast<_Tp &, _A0>(0)) + { + }; - template (declval<_From>()))> - static integral_constant::value && !__is_invalid_lvalue_to_rvalue_cast<_To, _From>::value> __test_cast( - long); - - template - static false_type __test_cast(...); - - template ()...))> - static true_type __test_nary(int); - template - static false_type __test_nary(...); - - template ()))> - static is_destructible<_Tp> __test_unary(int); - template - static false_type __test_unary(...); -}; - -template ::value> -struct __is_default_constructible : decltype(__is_constructible_helper::__test_nary<_Tp>(0)) -{ -}; - -template -struct __is_default_constructible<_Tp, true> : false_type -{ -}; - -template -struct __is_default_constructible<_Tp[], false> : false_type -{ -}; - -template -struct __is_default_constructible<_Tp[_Nx], false> : __is_default_constructible::type> -{ -}; - -template -struct __libcpp_is_constructible -{ - static_assert(sizeof...(_Args) > 1, "Wrong specialization"); - typedef decltype(__is_constructible_helper::__test_nary<_Tp, _Args...>(0)) type; -}; - -template -struct __libcpp_is_constructible<_Tp> : __is_default_constructible<_Tp> -{ -}; - -template -struct __libcpp_is_constructible<_Tp, _A0> : public decltype(__is_constructible_helper::__test_unary<_Tp, _A0>(0)) -{ -}; - -template -struct __libcpp_is_constructible<_Tp&, _A0> : public decltype(__is_constructible_helper::__test_cast<_Tp&, _A0>(0)) -{ -}; - -template -struct __libcpp_is_constructible<_Tp&&, _A0> : public decltype(__is_constructible_helper::__test_cast<_Tp&&, _A0>(0)) -{ -}; + template + struct __libcpp_is_constructible<_Tp &&, _A0> + : public decltype(__is_constructible_helper::__test_cast<_Tp &&, _A0>(0)) + { + }; #endif #if __WI_HAS_FEATURE_IS_CONSTRUCTIBLE -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible : public integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible : public integral_constant + { + }; #elif !defined(__WI_LIBCPP_CXX03_LANG) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible : public __libcpp_is_constructible<_Tp, _Args...>::type -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible : public __libcpp_is_constructible<_Tp, _Args...>::type + { + }; #else -// template struct is_constructible0; + // template struct is_constructible0; -// main is_constructible0 test + // main is_constructible0 test -template -decltype((_Tp(), true_type())) __is_constructible0_test(_Tp&); + template decltype((_Tp(), true_type())) __is_constructible0_test(_Tp &); -false_type __is_constructible0_test(__any); + false_type __is_constructible0_test(__any); -template -decltype((_Tp(declval<_A0>()), true_type())) __is_constructible1_test(_Tp&, _A0&); + template decltype((_Tp(declval<_A0>()), true_type())) __is_constructible1_test(_Tp &, _A0 &); -template -false_type __is_constructible1_test(__any, _A0&); + template false_type __is_constructible1_test(__any, _A0 &); -template -decltype((_Tp(declval<_A0>(), declval<_A1>()), true_type())) __is_constructible2_test(_Tp&, _A0&, _A1&); + template + decltype((_Tp(declval<_A0>(), declval<_A1>()), true_type())) __is_constructible2_test(_Tp &, _A0 &, _A1 &); -template -false_type __is_constructible2_test(__any, _A0&, _A1&); + template false_type __is_constructible2_test(__any, _A0 &, _A1 &); -template -decltype((_Tp(declval<_A0>(), declval<_A1>(), declval<_A2>()), true_type())) __is_constructible3_test(_Tp&, _A0&, _A1&, _A2&); + template + decltype((_Tp(declval<_A0>(), declval<_A1>(), declval<_A2>()), true_type())) __is_constructible3_test(_Tp &, _A0 &, + _A1 &, _A2 &); -template -false_type __is_constructible3_test(__any, _A0&, _A1&, _A2&); + template false_type __is_constructible3_test(__any, _A0 &, _A1 &, _A2 &); -template -struct __is_constructible0_imp // false, _Tp is not a scalar - : public common_type()))>::type -{ -}; + template + struct __is_constructible0_imp // false, _Tp is not a scalar + : public common_type()))>::type + { + }; -template -struct __is_constructible1_imp // false, _Tp is not a scalar - : public common_type(), declval<_A0&>()))>::type -{ -}; + template + struct __is_constructible1_imp // false, _Tp is not a scalar + : public common_type(), declval<_A0 &>()))>::type + { + }; -template -struct __is_constructible2_imp // false, _Tp is not a scalar - : public common_type(), declval<_A0>(), declval<_A1>()))>::type -{ -}; + template + struct __is_constructible2_imp // false, _Tp is not a scalar + : public common_type(), declval<_A0>(), declval<_A1>()))>::type + { + }; -template -struct __is_constructible3_imp // false, _Tp is not a scalar - : public common_type(), declval<_A0>(), declval<_A1>(), declval<_A2>()))>::type -{ -}; + template + struct __is_constructible3_imp // false, _Tp is not a scalar + : public common_type(), declval<_A0>(), declval<_A1>(), + declval<_A2>()))>::type + { + }; -// handle scalars and reference types + // handle scalars and reference types -// Scalars are default constructible, references are not + // Scalars are default constructible, references are not -template -struct __is_constructible0_imp : public is_scalar<_Tp> -{ -}; + template struct __is_constructible0_imp : public is_scalar<_Tp> + { + }; -template -struct __is_constructible1_imp : public is_convertible<_A0, _Tp> -{ -}; + template struct __is_constructible1_imp : public is_convertible<_A0, _Tp> + { + }; -template -struct __is_constructible2_imp : public false_type -{ -}; + template struct __is_constructible2_imp : public false_type + { + }; -template -struct __is_constructible3_imp : public false_type -{ -}; + template + struct __is_constructible3_imp : public false_type + { + }; -// Treat scalars and reference types separately + // Treat scalars and reference types separately -template -struct __is_constructible0_void_check : public __is_constructible0_imp::value || is_reference<_Tp>::value, _Tp> -{ -}; + template + struct __is_constructible0_void_check + : public __is_constructible0_imp::value || is_reference<_Tp>::value, _Tp> + { + }; -template -struct __is_constructible1_void_check : public __is_constructible1_imp::value || is_reference<_Tp>::value, _Tp, _A0> -{ -}; + template + struct __is_constructible1_void_check + : public __is_constructible1_imp::value || is_reference<_Tp>::value, _Tp, _A0> + { + }; -template -struct __is_constructible2_void_check - : public __is_constructible2_imp::value || is_reference<_Tp>::value, _Tp, _A0, _A1> -{ -}; + template + struct __is_constructible2_void_check + : public __is_constructible2_imp::value || is_reference<_Tp>::value, _Tp, _A0, _A1> + { + }; -template -struct __is_constructible3_void_check - : public __is_constructible3_imp::value || is_reference<_Tp>::value, _Tp, _A0, _A1, _A2> -{ -}; + template + struct __is_constructible3_void_check + : public __is_constructible3_imp::value || is_reference<_Tp>::value, _Tp, _A0, _A1, _A2> + { + }; -// If any of T or Args is void, is_constructible should be false + // If any of T or Args is void, is_constructible should be false -template -struct __is_constructible0_void_check : public false_type -{ -}; + template struct __is_constructible0_void_check : public false_type + { + }; -template -struct __is_constructible1_void_check : public false_type -{ -}; + template struct __is_constructible1_void_check : public false_type + { + }; -template -struct __is_constructible2_void_check : public false_type -{ -}; + template + struct __is_constructible2_void_check : public false_type + { + }; -template -struct __is_constructible3_void_check : public false_type -{ -}; + template + struct __is_constructible3_void_check : public false_type + { + }; -// is_constructible entry point + // is_constructible entry point -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible - : public __is_constructible3_void_check< - is_void<_Tp>::value || is_abstract<_Tp>::value || is_function<_Tp>::value || is_void<_A0>::value || is_void<_A1>::value || is_void<_A2>::value, - _Tp, - _A0, - _A1, - _A2> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible + : public __is_constructible3_void_check::value || is_abstract<_Tp>::value || + is_function<_Tp>::value || is_void<_A0>::value || + is_void<_A1>::value || is_void<_A2>::value, + _Tp, _A0, _A1, _A2> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> - : public __is_constructible0_void_check::value || is_abstract<_Tp>::value || is_function<_Tp>::value, _Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> + : public __is_constructible0_void_check< + is_void<_Tp>::value || is_abstract<_Tp>::value || is_function<_Tp>::value, _Tp> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, __is_construct::__nat> - : public __is_constructible1_void_check::value || is_abstract<_Tp>::value || is_function<_Tp>::value || is_void<_A0>::value, _Tp, _A0> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, __is_construct::__nat> + : public __is_constructible1_void_check::value || is_abstract<_Tp>::value || + is_function<_Tp>::value || is_void<_A0>::value, + _Tp, _A0> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, _A1, __is_construct::__nat> - : public __is_constructible2_void_check::value || is_abstract<_Tp>::value || is_function<_Tp>::value || is_void<_A0>::value || is_void<_A1>::value, _Tp, _A0, _A1> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, _A1, __is_construct::__nat> + : public __is_constructible2_void_check::value || is_abstract<_Tp>::value || + is_function<_Tp>::value || is_void<_A0>::value || + is_void<_A1>::value, + _Tp, _A0, _A1> + { + }; -// Array types are default constructible if their element type -// is default constructible + // Array types are default constructible if their element type + // is default constructible -template -struct __is_constructible0_imp : public is_constructible::type> -{ -}; + template + struct __is_constructible0_imp : public is_constructible::type> + { + }; -template -struct __is_constructible1_imp : public false_type -{ -}; + template struct __is_constructible1_imp : public false_type + { + }; -template -struct __is_constructible2_imp : public false_type -{ -}; + template + struct __is_constructible2_imp : public false_type + { + }; -template -struct __is_constructible3_imp : public false_type -{ -}; + template + struct __is_constructible3_imp : public false_type + { + }; -// Incomplete array types are not constructible + // Incomplete array types are not constructible -template -struct __is_constructible0_imp : public false_type -{ -}; + template struct __is_constructible0_imp : public false_type + { + }; -template -struct __is_constructible1_imp : public false_type -{ -}; + template struct __is_constructible1_imp : public false_type + { + }; -template -struct __is_constructible2_imp : public false_type -{ -}; + template + struct __is_constructible2_imp : public false_type + { + }; -template -struct __is_constructible3_imp : public false_type -{ -}; + template + struct __is_constructible3_imp : public false_type + { + }; #endif // __WI_HAS_FEATURE_IS_CONSTRUCTIBLE -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_constructible_v = is_constructible<_Tp, _Args...>::value; +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && \ + !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_constructible_v = is_constructible<_Tp, _Args...>::value; #endif -// is_default_constructible + // is_default_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_default_constructible : public is_constructible<_Tp> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_default_constructible : public is_constructible<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_default_constructible_v = is_default_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_default_constructible_v = is_default_constructible<_Tp>::value; #endif -// is_copy_constructible + // is_copy_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_copy_constructible - : public is_constructible<_Tp, typename add_lvalue_reference::type>::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_copy_constructible + : public is_constructible<_Tp, typename add_lvalue_reference::type>::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_constructible_v = is_copy_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_constructible_v = is_copy_constructible<_Tp>::value; #endif -// is_move_constructible + // is_move_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_move_constructible + template + struct __WI_LIBCPP_TEMPLATE_VIS is_move_constructible #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> + : public is_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> #else - : public is_copy_constructible<_Tp> + : public is_copy_constructible<_Tp> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_constructible_v = is_move_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_constructible_v = is_move_constructible<_Tp>::value; #endif -// is_trivially_constructible + // is_trivially_constructible #ifndef __WI_LIBCPP_HAS_NO_VARIADICS #if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible : integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible + : integral_constant + { + }; #else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible : false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible : false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp> #if __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template + template #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&&> + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp &&> #else -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp> + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp> #endif - : integral_constant::value> -{ -}; + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&> : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp &> + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&> : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp &> + : integral_constant::value> + { + }; #endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE #else // __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible : false_type -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible : false_type + { + }; #if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> - : integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> + : integral_constant + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, __is_construct::__nat> - : integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, __is_construct::__nat> + : integral_constant + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, __is_construct::__nat> - : integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp &, __is_construct::__nat> + : integral_constant + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, __is_construct::__nat> - : integral_constant -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp &, __is_construct::__nat> + : integral_constant + { + }; #else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> - : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, __is_construct::__nat> - : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, __is_construct::__nat> + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, __is_construct::__nat> - : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp &, __is_construct::__nat> + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, __is_construct::__nat> - : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp &, __is_construct::__nat> + : integral_constant::value> + { + }; #endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE #endif // __WI_LIBCPP_HAS_NO_VARIADICS -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_constructible_v = is_trivially_constructible<_Tp, _Args...>::value; +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && \ + !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_constructible_v = + is_trivially_constructible<_Tp, _Args...>::value; #endif -// is_trivially_default_constructible + // is_trivially_default_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_default_constructible : public is_trivially_constructible<_Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_default_constructible : public is_trivially_constructible<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_default_constructible_v = is_trivially_default_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_default_constructible_v = + is_trivially_default_constructible<_Tp>::value; #endif -// is_trivially_copy_constructible + // is_trivially_copy_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_constructible - : public is_trivially_constructible<_Tp, typename add_lvalue_reference::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_constructible + : public is_trivially_constructible<_Tp, typename add_lvalue_reference::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_constructible_v = is_trivially_copy_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_constructible_v = + is_trivially_copy_constructible<_Tp>::value; #endif -// is_trivially_move_constructible + // is_trivially_move_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_constructible + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_constructible #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_trivially_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> + : public is_trivially_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> #else - : public is_trivially_copy_constructible<_Tp> + : public is_trivially_copy_constructible<_Tp> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_constructible_v = is_trivially_move_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_constructible_v = + is_trivially_move_constructible<_Tp>::value; #endif -// is_trivially_assignable + // is_trivially_assignable #if __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE || __WI_GNUC_VER >= 501 -template -struct is_trivially_assignable : integral_constant -{ -}; + template + struct is_trivially_assignable : integral_constant + { + }; #else // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE -template -struct is_trivially_assignable : public false_type -{ -}; + template struct is_trivially_assignable : public false_type + { + }; -template -struct is_trivially_assignable<_Tp&, _Tp> : integral_constant::value> -{ -}; + template struct is_trivially_assignable<_Tp &, _Tp> : integral_constant::value> + { + }; -template -struct is_trivially_assignable<_Tp&, _Tp&> : integral_constant::value> -{ -}; + template struct is_trivially_assignable<_Tp &, _Tp &> : integral_constant::value> + { + }; -template -struct is_trivially_assignable<_Tp&, const _Tp&> : integral_constant::value> -{ -}; + template + struct is_trivially_assignable<_Tp &, const _Tp &> : integral_constant::value> + { + }; #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct is_trivially_assignable<_Tp&, _Tp&&> : integral_constant::value> -{ -}; + template struct is_trivially_assignable<_Tp &, _Tp &&> : integral_constant::value> + { + }; #endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES #endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_assignable_v = is_trivially_assignable<_Tp, _Arg>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_assignable_v = + is_trivially_assignable<_Tp, _Arg>::value; #endif -// is_trivially_copy_assignable + // is_trivially_copy_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_assignable - : public is_trivially_assignable::type, typename add_lvalue_reference::type>::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_assignable + : public is_trivially_assignable::type, + typename add_lvalue_reference::type>::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_assignable_v = is_trivially_copy_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_assignable_v = + is_trivially_copy_assignable<_Tp>::value; #endif -// is_trivially_move_assignable + // is_trivially_move_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_assignable : public is_trivially_assignable< - typename add_lvalue_reference<_Tp>::type, + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_assignable + : public is_trivially_assignable::type, #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - typename add_rvalue_reference<_Tp>::type> + typename add_rvalue_reference<_Tp>::type> #else - typename add_lvalue_reference<_Tp>::type> + typename add_lvalue_reference<_Tp>::type> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_assignable_v = is_trivially_move_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_assignable_v = + is_trivially_move_assignable<_Tp>::value; #endif -// is_trivially_destructible + // is_trivially_destructible #if __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible - : public integral_constant::value&& __has_trivial_destructor(_Tp)> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible + : public integral_constant::value &&__has_trivial_destructor(_Tp)> + { + }; #else -template -struct __libcpp_trivial_destructor : public integral_constant::value || is_reference<_Tp>::value> -{ -}; + template + struct __libcpp_trivial_destructor + : public integral_constant::value || is_reference<_Tp>::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible : public __libcpp_trivial_destructor::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible + : public __libcpp_trivial_destructor::type> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible<_Tp[]> : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible<_Tp[]> : public false_type + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_destructible_v = is_trivially_destructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_destructible_v = + is_trivially_destructible<_Tp>::value; #endif -// is_nothrow_constructible + // is_nothrow_constructible #if 0 template @@ -3906,271 +3581,273 @@ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_destructible_v = #if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) -template -struct __libcpp_is_nothrow_constructible; + template struct __libcpp_is_nothrow_constructible; -template -struct __libcpp_is_nothrow_constructible - : public integral_constant()...))> -{ -}; + template + struct __libcpp_is_nothrow_constructible + : public integral_constant()...))> + { + }; -template -void __implicit_conversion_to(_Tp) noexcept -{ -} + template void __implicit_conversion_to(_Tp) noexcept + { + } -template -struct __libcpp_is_nothrow_constructible - : public integral_constant(declval<_Arg>()))> -{ -}; + template + struct __libcpp_is_nothrow_constructible + : public integral_constant(declval<_Arg>()))> + { + }; -template -struct __libcpp_is_nothrow_constructible : public false_type -{ -}; + template + struct __libcpp_is_nothrow_constructible + : public false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible - : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp, _Args...> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible + : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp, + _Args...> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp[_Ns]> - : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp[_Ns]> + : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp> + { + }; #else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible : false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible : false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp> #if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template + template #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&&> + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp &&> #else -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp> + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp> #endif #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp &> #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp &> #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; #endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) #else // __WI_LIBCPP_HAS_NO_VARIADICS -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible : false_type -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible : false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> #if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp, __is_construct::__nat> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp, __is_construct::__nat> #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&, __is_construct::__nat> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp &, __is_construct::__nat> #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&, __is_construct::__nat> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp &, __is_construct::__nat> #if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant + : integral_constant #else - : integral_constant::value> + : integral_constant::value> #endif -{ -}; + { + }; #endif // __WI_LIBCPP_HAS_NO_VARIADICS #endif // __has_feature(is_nothrow_constructible) -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_constructible_v = is_nothrow_constructible<_Tp, _Args...>::value; +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && \ + !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_constructible_v = + is_nothrow_constructible<_Tp, _Args...>::value; #endif -// is_nothrow_default_constructible + // is_nothrow_default_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_default_constructible : public is_nothrow_constructible<_Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_default_constructible : public is_nothrow_constructible<_Tp> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_default_constructible_v = is_nothrow_default_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_default_constructible_v = + is_nothrow_default_constructible<_Tp>::value; #endif -// is_nothrow_copy_constructible + // is_nothrow_copy_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_constructible - : public is_nothrow_constructible<_Tp, typename add_lvalue_reference::type>::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_constructible + : public is_nothrow_constructible<_Tp, typename add_lvalue_reference::type>::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_constructible_v = is_nothrow_copy_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_constructible_v = + is_nothrow_copy_constructible<_Tp>::value; #endif -// is_nothrow_move_constructible + // is_nothrow_move_constructible -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_constructible + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_constructible #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_nothrow_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> + : public is_nothrow_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> #else - : public is_nothrow_copy_constructible<_Tp> + : public is_nothrow_copy_constructible<_Tp> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_constructible_v = + is_nothrow_move_constructible<_Tp>::value; #endif -// is_nothrow_assignable + // is_nothrow_assignable #if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) -template -struct __libcpp_is_nothrow_assignable; + template struct __libcpp_is_nothrow_assignable; -template -struct __libcpp_is_nothrow_assignable : public false_type -{ -}; + template struct __libcpp_is_nothrow_assignable : public false_type + { + }; -template -struct __libcpp_is_nothrow_assignable : public integral_constant() = declval<_Arg>())> -{ -}; + template + struct __libcpp_is_nothrow_assignable + : public integral_constant() = declval<_Arg>())> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable - : public __libcpp_is_nothrow_assignable::value, _Tp, _Arg> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable + : public __libcpp_is_nothrow_assignable::value, _Tp, _Arg> + { + }; #else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable : public false_type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp &, _Tp> #if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant -{ -}; + : integral_constant + { + }; #else - : integral_constant::value> -{ -}; + : integral_constant::value> + { + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp&> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp &, _Tp &> #if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant -{ -}; + : integral_constant + { + }; #else - : integral_constant::value> -{ -}; + : integral_constant::value> + { + }; #endif -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, const _Tp&> + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp &, const _Tp &> #if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant -{ -}; + : integral_constant + { + }; #else - : integral_constant::value> -{ -}; + : integral_constant::value> + { + }; #endif #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct is_nothrow_assignable<_Tp&, _Tp&&> + template + struct is_nothrow_assignable<_Tp &, _Tp &&> #if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant -{ -}; + : integral_constant + { + }; #else - : integral_constant::value> -{ -}; + : integral_constant::value> + { + }; #endif #endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -4178,780 +3855,782 @@ struct is_nothrow_assignable<_Tp&, _Tp&&> #endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_assignable_v = is_nothrow_assignable<_Tp, _Arg>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_assignable_v = is_nothrow_assignable<_Tp, _Arg>::value; #endif -// is_nothrow_copy_assignable + // is_nothrow_copy_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_assignable - : public is_nothrow_assignable::type, typename add_lvalue_reference::type>::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_assignable + : public is_nothrow_assignable::type, + typename add_lvalue_reference::type>::type> + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_assignable_v = is_nothrow_copy_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_assignable_v = + is_nothrow_copy_assignable<_Tp>::value; #endif -// is_nothrow_move_assignable + // is_nothrow_move_assignable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_assignable : public is_nothrow_assignable< - typename add_lvalue_reference<_Tp>::type, + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_assignable + : public is_nothrow_assignable::type, #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - typename add_rvalue_reference<_Tp>::type> + typename add_rvalue_reference<_Tp>::type> #else - typename add_lvalue_reference<_Tp>::type> + typename add_lvalue_reference<_Tp>::type> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_assignable_v = is_nothrow_move_assignable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_assignable_v = + is_nothrow_move_assignable<_Tp>::value; #endif -// is_nothrow_destructible + // is_nothrow_destructible #if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) -template -struct __libcpp_is_nothrow_destructible; + template struct __libcpp_is_nothrow_destructible; -template -struct __libcpp_is_nothrow_destructible : public false_type -{ -}; + template struct __libcpp_is_nothrow_destructible : public false_type + { + }; -template -struct __libcpp_is_nothrow_destructible : public integral_constant().~_Tp())> -{ -}; + template + struct __libcpp_is_nothrow_destructible : public integral_constant().~_Tp())> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible : public __libcpp_is_nothrow_destructible::value, _Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible + : public __libcpp_is_nothrow_destructible::value, _Tp> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[_Ns]> : public is_nothrow_destructible<_Tp> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[_Ns]> : public is_nothrow_destructible<_Tp> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp &> : public true_type + { + }; #ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&&> : public true_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp &&> : public true_type + { + }; #endif #else -template -struct __libcpp_nothrow_destructor : public integral_constant::value || is_reference<_Tp>::value> -{ -}; + template + struct __libcpp_nothrow_destructor + : public integral_constant::value || is_reference<_Tp>::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible : public __libcpp_nothrow_destructor::type> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible + : public __libcpp_nothrow_destructor::type> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[]> : public false_type -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[]> : public false_type + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_destructible_v = is_nothrow_destructible<_Tp>::value; #endif -// is_pod + // is_pod #if __WI_HAS_FEATURE_IS_POD || (__WI_GNUC_VER >= 403) -template -struct __WI_LIBCPP_TEMPLATE_VIS is_pod : public integral_constant -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_pod : public integral_constant + { + }; #else -template -struct __WI_LIBCPP_TEMPLATE_VIS is_pod - : public integral_constant< - bool, - is_trivially_default_constructible<_Tp>::value && is_trivially_copy_constructible<_Tp>::value && - is_trivially_copy_assignable<_Tp>::value && is_trivially_destructible<_Tp>::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_pod + : public integral_constant< + bool, is_trivially_default_constructible<_Tp>::value && is_trivially_copy_constructible<_Tp>::value && + is_trivially_copy_assignable<_Tp>::value && is_trivially_destructible<_Tp>::value> + { + }; #endif #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pod_v = is_pod<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pod_v = is_pod<_Tp>::value; #endif -// is_literal_type; + // is_literal_type; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_literal_type + template + struct __WI_LIBCPP_TEMPLATE_VIS is_literal_type #ifdef __WI_LIBCPP_IS_LITERAL - : public integral_constant + : public integral_constant #else - : integral_constant::type>::value || is_reference::type>::value> + : integral_constant::type>::value || + is_reference::type>::value> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_literal_type_v = is_literal_type<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_literal_type_v = is_literal_type<_Tp>::value; #endif -// is_standard_layout; + // is_standard_layout; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_standard_layout + template + struct __WI_LIBCPP_TEMPLATE_VIS is_standard_layout #if __WI_HAS_FEATURE_IS_STANDARD_LAYOUT || (__WI_GNUC_VER >= 407) - : public integral_constant + : public integral_constant #else - : integral_constant::type>::value> + : integral_constant::type>::value> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_standard_layout_v = is_standard_layout<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_standard_layout_v = is_standard_layout<_Tp>::value; #endif -// is_trivially_copyable; + // is_trivially_copyable; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copyable + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copyable #if __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE - : public integral_constant + : public integral_constant #elif __WI_GNUC_VER >= 501 - : public integral_constant::value && __is_trivially_copyable(_Tp)> + : public integral_constant::value && __is_trivially_copyable(_Tp)> #else - : integral_constant::type>::value> + : integral_constant::type>::value> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copyable_v = is_trivially_copyable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copyable_v = is_trivially_copyable<_Tp>::value; #endif -// is_trivial; + // is_trivial; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_trivial + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivial #if __WI_HAS_FEATURE_IS_TRIVIAL || __WI_GNUC_VER >= 407 - : public integral_constant + : public integral_constant #else - : integral_constant::value && is_trivially_default_constructible<_Tp>::value> + : integral_constant::value && is_trivially_default_constructible<_Tp>::value> #endif -{ -}; + { + }; #if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) -template -__WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivial_v = is_trivial<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivial_v = is_trivial<_Tp>::value; #endif -template -struct __is_reference_wrapper_impl : public false_type -{ -}; -template -struct __is_reference_wrapper_impl> : public true_type -{ -}; -template -struct __is_reference_wrapper : public __is_reference_wrapper_impl::type> -{ -}; + template struct __is_reference_wrapper_impl : public false_type + { + }; + template struct __is_reference_wrapper_impl> : public true_type + { + }; + template + struct __is_reference_wrapper : public __is_reference_wrapper_impl::type> + { + }; #ifndef __WI_LIBCPP_CXX03_LANG -template ::type, class _DecayA0 = typename decay<_A0>::type, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> -using __enable_if_bullet1 = - typename enable_if::value && is_base_of<_ClassT, _DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet1 = + typename enable_if::value && is_base_of<_ClassT, _DecayA0>::value>::type; -template ::type, class _DecayA0 = typename decay<_A0>::type> -using __enable_if_bullet2 = - typename enable_if::value && __is_reference_wrapper<_DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type> + using __enable_if_bullet2 = typename enable_if::value && + __is_reference_wrapper<_DecayA0>::value>::type; -template ::type, class _DecayA0 = typename decay<_A0>::type, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> -using __enable_if_bullet3 = - typename enable_if::value && !is_base_of<_ClassT, _DecayA0>::value && !__is_reference_wrapper<_DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet3 = + typename enable_if::value && !is_base_of<_ClassT, _DecayA0>::value && + !__is_reference_wrapper<_DecayA0>::value>::type; -template ::type, class _DecayA0 = typename decay<_A0>::type, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> -using __enable_if_bullet4 = - typename enable_if::value && is_base_of<_ClassT, _DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet4 = + typename enable_if::value && is_base_of<_ClassT, _DecayA0>::value>::type; -template ::type, class _DecayA0 = typename decay<_A0>::type> -using __enable_if_bullet5 = - typename enable_if::value && __is_reference_wrapper<_DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type> + using __enable_if_bullet5 = + typename enable_if::value && __is_reference_wrapper<_DecayA0>::value>::type; -template ::type, class _DecayA0 = typename decay<_A0>::type, class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> -using __enable_if_bullet6 = - typename enable_if::value && !is_base_of<_ClassT, _DecayA0>::value && !__is_reference_wrapper<_DecayA0>::value>::type; + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet6 = + typename enable_if::value && !is_base_of<_ClassT, _DecayA0>::value && + !__is_reference_wrapper<_DecayA0>::value>::type; -// __invoke forward declarations + // __invoke forward declarations -// fall back - none of the bullets + // fall back - none of the bullets -#define __WI_LIBCPP_INVOKE_RETURN(...) \ - __WI_NOEXCEPT_(__WI_NOEXCEPT_(__VA_ARGS__))->decltype(__VA_ARGS__) \ - { \ - return __VA_ARGS__; \ +#define __WI_LIBCPP_INVOKE_RETURN(...) \ + __WI_NOEXCEPT_(__WI_NOEXCEPT_(__VA_ARGS__))->decltype(__VA_ARGS__) \ + { \ + return __VA_ARGS__; \ } -template -auto __invoke(__any, _Args&&... __args) -> __nat; + template auto __invoke(__any, _Args &&...__args) -> __nat; -template -auto __invoke_constexpr(__any, _Args&&... __args) -> __nat; + template auto __invoke_constexpr(__any, _Args &&...__args) -> __nat; -// bullets 1, 2 and 3 + // bullets 1, 2 and 3 -template > -inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp &&__f, _A0 &&__a0, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&&... __args) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0, _Args &&...__args) __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) template > - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0, _Args&&... __args) + inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp &&__f, _A0 &&__a0, _Args &&...__args) __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) template > inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - auto __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) + auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp &&__f, _A0 &&__a0, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - auto __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) - // bullets 4, 5 and 6 - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0) __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) + // bullets 4, 5 and 6 template > - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - auto __invoke_constexpr(_Fp&& __f, _A0&& __a0) __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) + inline __WI_LIBCPP_INLINE_VISIBILITY + auto __invoke(_Fp &&__f, _A0 &&__a0) __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0) __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto __invoke(_Fp &&__f, _A0 &&__a0) __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) template > - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - auto __invoke_constexpr(_Fp&& __f, _A0&& __a0) __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0) + __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto __invoke(_Fp &&__f, _A0 &&__a0) __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) - template > - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) + template > + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp &&__f, _A0 &&__a0) + __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) - // bullet 7 + // bullet 7 - template - inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp&& __f, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) + template + inline __WI_LIBCPP_INLINE_VISIBILITY auto __invoke(_Fp &&__f, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR auto __invoke_constexpr(_Fp&& __f, _Args&&... __args) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + auto __invoke_constexpr(_Fp &&__f, _Args &&...__args) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) #undef __WI_LIBCPP_INVOKE_RETURN - // __invokable + // __invokable + + template + struct __invokable_r + { + // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void, + // or incomplete array types as required by the standard. + using _Result = decltype(__invoke(declval<_Fp>(), declval<_Args>()...)); + + using type = typename conditional< + !is_same<_Result, __nat>::value, + typename conditional::value, true_type, is_convertible<_Result, _Ret>>::type, + false_type>::type; + static const bool value = type::value; + }; + + template using __invokable = __invokable_r; + + template struct __nothrow_invokable_r_imp + { + static const bool value = false; + }; + + template struct __nothrow_invokable_r_imp + { + typedef __nothrow_invokable_r_imp _ThisT; + + template static void __test_noexcept(_Tp) noexcept; + + static const bool value = + noexcept(_ThisT::__test_noexcept<_Ret>(__invoke(declval<_Fp>(), declval<_Args>()...))); + }; + + template struct __nothrow_invokable_r_imp + { + static const bool value = noexcept(__invoke(declval<_Fp>(), declval<_Args>()...)); + }; template - struct __invokable_r -{ - // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void, - // or incomplete array types as required by the standard. - using _Result = decltype(__invoke(declval<_Fp>(), declval<_Args>()...)); + using __nothrow_invokable_r = + __nothrow_invokable_r_imp<__invokable_r<_Ret, _Fp, _Args...>::value, is_void<_Ret>::value, _Ret, _Fp, _Args...>; - using type = - typename conditional::value, typename conditional::value, true_type, is_convertible<_Result, _Ret>>::type, false_type>::type; - static const bool value = type::value; -}; + template + using __nothrow_invokable = __nothrow_invokable_r_imp<__invokable<_Fp, _Args...>::value, true, void, _Fp, _Args...>; -template -using __invokable = __invokable_r; + template + struct __invoke_of + : public enable_if<__invokable<_Fp, _Args...>::value, typename __invokable_r::_Result> + { + }; -template -struct __nothrow_invokable_r_imp -{ - static const bool value = false; -}; + // result_of -template -struct __nothrow_invokable_r_imp -{ - typedef __nothrow_invokable_r_imp _ThisT; - - template - static void __test_noexcept(_Tp) noexcept; - - static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>(__invoke(declval<_Fp>(), declval<_Args>()...))); -}; - -template -struct __nothrow_invokable_r_imp -{ - static const bool value = noexcept(__invoke(declval<_Fp>(), declval<_Args>()...)); -}; - -template -using __nothrow_invokable_r = - __nothrow_invokable_r_imp<__invokable_r<_Ret, _Fp, _Args...>::value, is_void<_Ret>::value, _Ret, _Fp, _Args...>; - -template -using __nothrow_invokable = __nothrow_invokable_r_imp<__invokable<_Fp, _Args...>::value, true, void, _Fp, _Args...>; - -template -struct __invoke_of : public enable_if<__invokable<_Fp, _Args...>::value, typename __invokable_r::_Result> -{ -}; - -// result_of - -template -class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fp(_Args...)> : public __invoke_of<_Fp, _Args...> -{ -}; + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fp(_Args...)> : public __invoke_of<_Fp, _Args...> + { + }; #if __WI_LIBCPP_STD_VER > 11 -template -using result_of_t = typename result_of<_Tp>::type; + template using result_of_t = typename result_of<_Tp>::type; #endif #if __WI_LIBCPP_STD_VER > 14 -// invoke_result + // invoke_result -template -struct __WI_LIBCPP_TEMPLATE_VIS invoke_result : __invoke_of<_Fn, _Args...> -{ -}; + template struct __WI_LIBCPP_TEMPLATE_VIS invoke_result : __invoke_of<_Fn, _Args...> + { + }; -template -using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; + template using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; -// is_invocable + // is_invocable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_invocable : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_invocable : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_invocable_r : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_invocable_r : integral_constant::value> + { + }; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value; -// is_nothrow_invocable + // is_nothrow_invocable -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable + : integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r : integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r + : integral_constant::value> + { + }; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; #endif // __WI_LIBCPP_STD_VER > 14 #endif // !defined(__WI_LIBCPP_CXX03_LANG) -template -struct __is_swappable; -template -struct __is_nothrow_swappable; + template struct __is_swappable; + template struct __is_nothrow_swappable; -template -inline __WI_LIBCPP_INLINE_VISIBILITY + template + inline __WI_LIBCPP_INLINE_VISIBILITY #ifndef __WI_LIBCPP_CXX03_LANG - typename enable_if::value && is_move_assignable<_Tp>::value>::type + typename enable_if::value && is_move_assignable<_Tp>::value>::type #else - void + void #endif - swap_wil(_Tp& __x, _Tp& __y) __WI_NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value&& is_nothrow_move_assignable<_Tp>::value) -{ - _Tp __t(wistd::move(__x)); - __x = wistd::move(__y); - __y = wistd::move(__t); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY _ForwardIterator2 swap_ranges_wil(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) -{ - for (; __first1 != __last1; ++__first1, (void)++__first2) - swap_wil(*__first1, *__first2); - return __first2; -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY typename enable_if<__is_swappable<_Tp>::value>::type swap_wil(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) - __WI_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) -{ - wistd::swap_ranges_wil(__a, __a + _Np, __b); -} - -template -inline __WI_LIBCPP_INLINE_VISIBILITY void iter_swap_wil(_ForwardIterator1 __a, _ForwardIterator2 __b) - // __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*__a, *__b))) - __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*declval<_ForwardIterator1>(), *declval<_ForwardIterator2>()))) -{ - swap_wil(*__a, *__b); -} - -// __swappable - -namespace __detail -{ - // ALL generic swap overloads MUST already have a declaration available at this point. - - template ::value && !is_void<_Up>::value> - struct __swappable_with + swap_wil(_Tp &__x, _Tp &__y) + __WI_NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value &&is_nothrow_move_assignable<_Tp>::value) { - template - static decltype(swap_wil(declval<_LHS>(), declval<_RHS>())) __test_swap(int); - template - static __nat __test_swap(long); + _Tp __t(wistd::move(__x)); + __x = wistd::move(__y); + __y = wistd::move(__t); + } - // Extra parens are needed for the C++03 definition of decltype. - typedef decltype((__test_swap<_Tp, _Up>(0))) __swap1; - typedef decltype((__test_swap<_Up, _Tp>(0))) __swap2; - - static const bool value = !is_same<__swap1, __nat>::value && !is_same<__swap2, __nat>::value; - }; - - template - struct __swappable_with<_Tp, _Up, false> : false_type + template + inline __WI_LIBCPP_INLINE_VISIBILITY _ForwardIterator2 swap_ranges_wil(_ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2) { - }; + for (; __first1 != __last1; ++__first1, (void)++__first2) + swap_wil(*__first1, *__first2); + return __first2; + } - template ::value> - struct __nothrow_swappable_with + template + inline __WI_LIBCPP_INLINE_VISIBILITY typename enable_if<__is_swappable<_Tp>::value>::type swap_wil(_Tp (&__a)[_Np], + _Tp (&__b)[_Np]) + __WI_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { - static const bool value = + wistd::swap_ranges_wil(__a, __a + _Np, __b); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY void iter_swap_wil(_ForwardIterator1 __a, _ForwardIterator2 __b) + // __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*__a, *__b))) + __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*declval<_ForwardIterator1>(), *declval<_ForwardIterator2>()))) + { + swap_wil(*__a, *__b); + } + + // __swappable + + namespace __detail + { + // ALL generic swap overloads MUST already have a declaration available at this point. + + template ::value && !is_void<_Up>::value> + struct __swappable_with + { + template + static decltype(swap_wil(declval<_LHS>(), declval<_RHS>())) __test_swap(int); + template static __nat __test_swap(long); + + // Extra parens are needed for the C++03 definition of decltype. + typedef decltype((__test_swap<_Tp, _Up>(0))) __swap1; + typedef decltype((__test_swap<_Up, _Tp>(0))) __swap2; + + static const bool value = !is_same<__swap1, __nat>::value && !is_same<__swap2, __nat>::value; + }; + + template struct __swappable_with<_Tp, _Up, false> : false_type + { + }; + + template ::value> + struct __nothrow_swappable_with + { + static const bool value = #ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT - noexcept(swap_wil(declval<_Tp>(), declval<_Up>())) && noexcept(swap_wil(declval<_Up>(), declval<_Tp>())); + noexcept(swap_wil(declval<_Tp>(), declval<_Up>())) && + noexcept(swap_wil(declval<_Up>(), declval<_Tp>())); #else - false; + false; #endif - }; + }; - template - struct __nothrow_swappable_with<_Tp, _Up, false> : false_type + template struct __nothrow_swappable_with<_Tp, _Up, false> : false_type + { + }; + + } // namespace __detail + + template + struct __is_swappable : public integral_constant::value> { }; -} // namespace __detail - -template -struct __is_swappable : public integral_constant::value> -{ -}; - -template -struct __is_nothrow_swappable : public integral_constant::value> -{ -}; + template + struct __is_nothrow_swappable : public integral_constant::value> + { + }; #if __WI_LIBCPP_STD_VER > 14 -template -struct __WI_LIBCPP_TEMPLATE_VIS is_swappable_with : public integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_swappable_with + : public integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_swappable - : public conditional<__is_referenceable<_Tp>::value, is_swappable_with::type, typename add_lvalue_reference<_Tp>::type>, false_type>::type -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_swappable + : public conditional< + __is_referenceable<_Tp>::value, + is_swappable_with::type, typename add_lvalue_reference<_Tp>::type>, + false_type>::type + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with - : public integral_constant::value> -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with + : public integral_constant::value> + { + }; -template -struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable - : public conditional<__is_referenceable<_Tp>::value, is_nothrow_swappable_with::type, typename add_lvalue_reference<_Tp>::type>, false_type>::type -{ -}; + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable + : public conditional<__is_referenceable<_Tp>::value, + is_nothrow_swappable_with::type, + typename add_lvalue_reference<_Tp>::type>, + false_type>::type + { + }; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_v = is_swappable<_Tp>::value; + template __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_v = is_swappable<_Tp>::value; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value; -template -__WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value; + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value; #endif // __WI_LIBCPP_STD_VER > 14 #ifdef __WI_LIBCPP_UNDERLYING_TYPE -template -struct underlying_type -{ - typedef __WI_LIBCPP_UNDERLYING_TYPE(_Tp) type; -}; + template struct underlying_type + { + typedef __WI_LIBCPP_UNDERLYING_TYPE(_Tp) type; + }; #if __WI_LIBCPP_STD_VER > 11 -template -using underlying_type_t = typename underlying_type<_Tp>::type; + template using underlying_type_t = typename underlying_type<_Tp>::type; #endif #else // __WI_LIBCPP_UNDERLYING_TYPE -template -struct underlying_type -{ - static_assert( - _Support, - "The underlying_type trait requires compiler " - "support. Either no such support exists or " - "libc++ does not know how to use it."); -}; + template struct underlying_type + { + static_assert(_Support, "The underlying_type trait requires compiler " + "support. Either no such support exists or " + "libc++ does not know how to use it."); + }; #endif // __WI_LIBCPP_UNDERLYING_TYPE -template ::value> -struct __sfinae_underlying_type -{ - typedef typename underlying_type<_Tp>::type type; - typedef decltype(((type)1) + 0) __promoted_type; -}; + template ::value> struct __sfinae_underlying_type + { + typedef typename underlying_type<_Tp>::type type; + typedef decltype(((type)1) + 0) __promoted_type; + }; -template -struct __sfinae_underlying_type<_Tp, false> -{ -}; + template struct __sfinae_underlying_type<_Tp, false> + { + }; -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR int __convert_to_integral(int __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR int __convert_to_integral(int __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned __convert_to_integral(unsigned __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned __convert_to_integral(unsigned __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR long __convert_to_integral(long __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR long __convert_to_integral(long __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned long __convert_to_integral(unsigned long __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned long __convert_to_integral(unsigned long __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR long long __convert_to_integral(long long __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR long long __convert_to_integral(long long __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned long long __convert_to_integral(unsigned long long __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR unsigned long long __convert_to_integral( + unsigned long long __val) + { + return __val; + } -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR typename enable_if::value, long long>::type __convert_to_integral(_Fp __val) -{ - return __val; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + typename enable_if::value, long long>::type + __convert_to_integral(_Fp __val) + { + return __val; + } #ifndef __WI_LIBCPP_HAS_NO_INT128 -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR __int128_t __convert_to_integral(__int128_t __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR __int128_t __convert_to_integral(__int128_t __val) + { + return __val; + } -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR __uint128_t __convert_to_integral(__uint128_t __val) -{ - return __val; -} + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR __uint128_t __convert_to_integral(__uint128_t __val) + { + return __val; + } #endif -template -inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR typename __sfinae_underlying_type<_Tp>::__promoted_type __convert_to_integral(_Tp __val) -{ - return __val; -} + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR typename __sfinae_underlying_type<_Tp>::__promoted_type + __convert_to_integral(_Tp __val) + { + return __val; + } #ifndef __WI_LIBCPP_CXX03_LANG -template -struct __has_operator_addressof_member_imp -{ - template - static auto __test(int) -> typename __select_2nd().operator&()), true_type>::type; - template - static auto __test(long) -> false_type; + template struct __has_operator_addressof_member_imp + { + template + static auto __test(int) -> typename __select_2nd().operator&()), true_type>::type; + template static auto __test(long) -> false_type; - static const bool value = decltype(__test<_Tp>(0))::value; -}; + static const bool value = decltype(__test<_Tp>(0))::value; + }; -template -struct __has_operator_addressof_free_imp -{ - template - static auto __test(int) -> typename __select_2nd())), true_type>::type; - template - static auto __test(long) -> false_type; + template struct __has_operator_addressof_free_imp + { + template + static auto __test(int) -> typename __select_2nd())), true_type>::type; + template static auto __test(long) -> false_type; - static const bool value = decltype(__test<_Tp>(0))::value; -}; + static const bool value = decltype(__test<_Tp>(0))::value; + }; -template -struct __has_operator_addressof - : public integral_constant::value || __has_operator_addressof_free_imp<_Tp>::value> -{ -}; + template + struct __has_operator_addressof : public integral_constant::value || + __has_operator_addressof_free_imp<_Tp>::value> + { + }; #endif // __WI_LIBCPP_CXX03_LANG #ifndef __WI_LIBCPP_CXX03_LANG -template -using void_t = void; + template using void_t = void; #ifndef __WI_LIBCPP_HAS_NO_VARIADICS -template -struct conjunction : __and_<_Args...> -{ -}; -template -__WI_LIBCPP_INLINE_VAR constexpr bool conjunction_v = conjunction<_Args...>::value; + template struct conjunction : __and_<_Args...> + { + }; + template __WI_LIBCPP_INLINE_VAR constexpr bool conjunction_v = conjunction<_Args...>::value; -template -struct disjunction : __or_<_Args...> -{ -}; -template -__WI_LIBCPP_INLINE_VAR constexpr bool disjunction_v = disjunction<_Args...>::value; + template struct disjunction : __or_<_Args...> + { + }; + template __WI_LIBCPP_INLINE_VAR constexpr bool disjunction_v = disjunction<_Args...>::value; -template -struct negation : __not_<_Tp> -{ -}; -template -__WI_LIBCPP_INLINE_VAR constexpr bool negation_v = negation<_Tp>::value; + template struct negation : __not_<_Tp> + { + }; + template __WI_LIBCPP_INLINE_VAR constexpr bool negation_v = negation<_Tp>::value; #endif // __WI_LIBCPP_HAS_NO_VARIADICS #endif // __WI_LIBCPP_CXX03_LANG // These traits are used in __tree and __hash_table #ifndef __WI_LIBCPP_CXX03_LANG -struct __extract_key_fail_tag -{ -}; -struct __extract_key_self_tag -{ -}; -struct __extract_key_first_tag -{ -}; + struct __extract_key_fail_tag + { + }; + struct __extract_key_self_tag + { + }; + struct __extract_key_first_tag + { + }; -template ::type> -struct __can_extract_key : conditional::value, __extract_key_self_tag, __extract_key_fail_tag>::type -{ -}; + template ::type> + struct __can_extract_key + : conditional::value, __extract_key_self_tag, __extract_key_fail_tag>::type + { + }; -template -struct __can_extract_key<_Pair, _Key, pair<_First, _Second>> - : conditional::type, _Key>::value, __extract_key_first_tag, __extract_key_fail_tag>::type -{ -}; + template + struct __can_extract_key<_Pair, _Key, pair<_First, _Second>> + : conditional::type, _Key>::value, __extract_key_first_tag, + __extract_key_fail_tag>::type + { + }; -// __can_extract_map_key uses true_type/false_type instead of the tags. -// It returns true if _Key != _ContainerValueTy (the container is a map not a set) -// and _ValTy == _Key. -template ::type> -struct __can_extract_map_key : integral_constant::value> -{ -}; + // __can_extract_map_key uses true_type/false_type instead of the tags. + // It returns true if _Key != _ContainerValueTy (the container is a map not a set) + // and _ValTy == _Key. + template ::type> + struct __can_extract_map_key : integral_constant::value> + { + }; -// This specialization returns __extract_key_fail_tag for non-map containers -// because _Key == _ContainerValueTy -template -struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy> : false_type -{ -}; + // This specialization returns __extract_key_fail_tag for non-map containers + // because _Key == _ContainerValueTy + template + struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy> : false_type + { + }; #endif #if __WI_LIBCPP_STD_VER > 17 -enum class endian -{ - little = 0xDEAD, - big = 0xFACE, + enum class endian + { + little = 0xDEAD, + big = 0xFACE, #if defined(__WI_LIBCPP_LITTLE_ENDIAN) - native = little + native = little #elif defined(__WI_LIBCPP_BIG_ENDIAN) - native = big + native = big #else - native = 0xCAFE + native = 0xCAFE #endif -}; + }; #endif } // namespace wistd /// @endcond diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wrl.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wrl.h index 846ea67..06e8adf 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wrl.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/wil/wrl.h @@ -13,10 +13,10 @@ #ifndef __WIL_WRL_INCLUDED #define __WIL_WRL_INCLUDED -#include +#include "common.h" // wistd type_traits helpers #include "result.h" -#include "common.h" // wistd type_traits helpers #include // GetModuleHandleW +#include /// @cond EXTERN_C IMAGE_DOS_HEADER __ImageBase; @@ -28,103 +28,102 @@ 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(L"input", true); -@endcode -*/ -template -Microsoft::WRL::ComPtr MakeAndInitializeOrThrow(TArgs&&... args) -{ - Microsoft::WRL::ComPtr obj; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&obj, Microsoft::WRL::Details::Forward(args)...)); - return obj; -} + /** 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(L"input", true); + @endcode + */ + template Microsoft::WRL::ComPtr MakeAndInitializeOrThrow(TArgs &&...args) + { + Microsoft::WRL::ComPtr obj; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&obj, Microsoft::WRL::Details::Forward(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(L"input", true); -@endcode -*/ -template -Microsoft::WRL::ComPtr 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::value, - // "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead"); - auto obj = Microsoft::WRL::Make(Microsoft::WRL::Details::Forward(args)...); - THROW_IF_NULL_ALLOC(obj.Get()); - 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(L"input", true); + @endcode + */ + template Microsoft::WRL::ComPtr 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::value, + // "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead"); + auto obj = Microsoft::WRL::Make(Microsoft::WRL::Details::Forward(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 -::Microsoft::WRL::ComPtr MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT -{ - using namespace Microsoft::WRL; - return Callback, TDelegateInterface, FtmBase>>(wistd::forward(args)...); -} + /** 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 + ::Microsoft::WRL::ComPtr MakeAgileCallbackNoThrow(Args &&...args) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + return Callback, TDelegateInterface, FtmBase>>( + wistd::forward(args)...); + } #ifdef WIL_ENABLE_EXCEPTIONS -template -::Microsoft::WRL::ComPtr MakeAgileCallback(Args&&... args) -{ - auto result = MakeAgileCallbackNoThrow(wistd::forward(args)...); - THROW_IF_NULL_ALLOC(result); - return result; -} + template + ::Microsoft::WRL::ComPtr MakeAgileCallback(Args &&...args) + { + auto result = MakeAgileCallbackNoThrow(wistd::forward(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() + /** 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 { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) - { - modulePtr->IncrementObjectCount(); - } - else + 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(&__ImageBase) == GetModuleHandleW(nullptr)); + // 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(&__ImageBase) == GetModuleHandleW(nullptr)); #endif + } } - } - wrl_module_reference(wrl_module_reference const&) : wrl_module_reference() - { - } - - ~wrl_module_reference() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + wrl_module_reference(wrl_module_reference const &) : wrl_module_reference() { - modulePtr->DecrementObjectCount(); } - } -}; + + ~wrl_module_reference() + { + if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) + { + modulePtr->DecrementObjectCount(); + } + } + }; } // namespace wil diff --git a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/xcom/base.h b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/xcom/base.h index b072c53..8bc2cd5 100644 --- a/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/xcom/base.h +++ b/projects/WinDurango.D3D11X/include/WinDurango.D3D11X/xcom/base.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include #include "wil/result_macros.h" +#include +#include +#include #ifdef _CPPRTTI #include #include @@ -11,9 +11,9 @@ #ifndef CINTERFACE struct IUnknownVtbl { - HRESULT(*QueryInterface)(IUnknown *, REFIID riid, void **ppvObject); - ULONG(*AddRef)(IUnknown *); - ULONG(*Release)(IUnknown *); + HRESULT (*QueryInterface)(IUnknown *, REFIID riid, void **ppvObject); + ULONG (*AddRef)(IUnknown *); + ULONG (*Release)(IUnknown *); }; #endif @@ -28,13 +28,14 @@ struct abi_t }; // {7E93844E-159A-4D07-9910-87E9D65ECE00} -static const GUID GUID_UnwrapInterface = { 0x7E93844E, 0x159A, 0x4D07, { 0x99, 0x10, 0x87, 0xE9, 0xD6, 0x5E, 0xCE, 0x00 } }; +static const GUID GUID_UnwrapInterface = {0x7E93844E, 0x159A, 0x4D07, {0x99, 0x10, 0x87, 0xE9, 0xD6, 0x5E, 0xCE, 0x00}}; -template -using reg_return_t = std::conditional_t<(std::is_class_v || std::is_union_v) && (sizeof(T) <= sizeof(std::uintptr_t)), std::uintptr_t, T>; +template +using reg_return_t = + std::conditional_t<(std::is_class_v || std::is_union_v) && (sizeof(T) <= sizeof(std::uintptr_t)), + std::uintptr_t, T>; -template -FORCEINLINE reg_return_t to_reg_return(T value) +template FORCEINLINE reg_return_t to_reg_return(T value) { if constexpr (std::is_same_v>) return value; @@ -48,37 +49,40 @@ namespace xcom { namespace impl { - template - inline constexpr GUID guid_v = __uuidof(T); + template inline constexpr GUID guid_v = __uuidof(T); } - template - inline constexpr GUID guid_of() { return impl::guid_v; } + template inline constexpr GUID guid_of() + { + return impl::guid_v; + } - template typename T> - inline constexpr GUID guid_of() { return guid_of>(); } + template