mirror of
https://github.com/WinDurango/WinDurango.git
synced 2026-01-31 00:55:17 +01:00
Ran clang-format.
This commit is contained in:
@@ -1,36 +1,41 @@
|
||||
/*
|
||||
* Created by DexrnZacAttack on 1/23/26 using zPc-i2.
|
||||
* WinDurango.Common::Config
|
||||
*/
|
||||
*/
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "Interfaces/Storage/File.h"
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Interfaces/Storage/File.h"
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
* TODO: Make it to write back
|
||||
*/
|
||||
namespace wd::common {
|
||||
class Config {
|
||||
public:
|
||||
Config() : pFile(nullptr), RO(false) {}
|
||||
Config(std::shared_ptr<interfaces::storage::File> file, bool ReadOnly = false) : pFile(file), RO(ReadOnly) {}
|
||||
*/
|
||||
namespace wd::common
|
||||
{
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
Config() : pFile(nullptr), RO(false)
|
||||
{
|
||||
}
|
||||
Config(std::shared_ptr<interfaces::storage::File> file, bool ReadOnly = false) : pFile(file), RO(ReadOnly)
|
||||
{
|
||||
}
|
||||
|
||||
bool parse();
|
||||
|
||||
/*
|
||||
* Operator Overloading
|
||||
* https://en.cppreference.com/w/cpp/language/operators.html
|
||||
*/
|
||||
template<typename T>
|
||||
T& operator[](std::string node);
|
||||
*/
|
||||
template <typename T> T &operator[](std::string node);
|
||||
|
||||
template<typename T>
|
||||
bool set(std::string node, T type);
|
||||
private:
|
||||
template <typename T> bool set(std::string node, T type);
|
||||
|
||||
private:
|
||||
std::shared_ptr<interfaces::storage::File> pFile;
|
||||
bool RO;
|
||||
nlohmann::json data;
|
||||
};
|
||||
}
|
||||
} // namespace wd::common
|
||||
|
||||
@@ -2,32 +2,38 @@
|
||||
// Created by DexrnZacAttack on 1/23/26 using zPc-i2.
|
||||
//
|
||||
#pragma once
|
||||
#include "File.h"
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#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<File> 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<File> 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<Directory> 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
|
||||
} // namespace wd::common::interfaces::storage
|
||||
@@ -1,17 +1,21 @@
|
||||
/*
|
||||
* wd::common::interfaces::storage::File
|
||||
*/
|
||||
*/
|
||||
#pragma once
|
||||
#include <istream>
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
} // namespace wd::common::interfaces::storage
|
||||
@@ -1,99 +1,140 @@
|
||||
/*
|
||||
* Logging File
|
||||
* WinDurango.Common::Logging
|
||||
*/
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <iostream>
|
||||
*/
|
||||
#include "WinDurango.Common/Interfaces/Storage/File.h"
|
||||
#include "WinDurango.Common/exports.h"
|
||||
#include <iostream>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace wd::common {
|
||||
class WD_API Logging {
|
||||
public:
|
||||
Logging() : pFile(nullptr), isConstructed(false) {}
|
||||
Logging(std::shared_ptr<interfaces::storage::File> file) : pFile(file), isConstructed(true) {}
|
||||
namespace wd::common
|
||||
{
|
||||
class WD_API Logging
|
||||
{
|
||||
public:
|
||||
Logging() : pFile(nullptr), isConstructed(false)
|
||||
{
|
||||
}
|
||||
Logging(std::shared_ptr<interfaces::storage::File> 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<typename... Args>
|
||||
void Log(std::string codespace, fmt::format_string<Args...> 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 <typename... Args> void Log(std::string codespace, fmt::format_string<Args...> 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>(args)...);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLogger(codespace);
|
||||
log[codespace]->info(fmt, std::forward<Args>(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<typename... Args>
|
||||
void Warn(std::string codespace, fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (!isInitialized) {
|
||||
template <typename... Args> void Warn(std::string codespace, fmt::format_string<Args...> 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>(args)...);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLogger(codespace);
|
||||
log[codespace]->warn(fmt, std::forward<Args>(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<typename... Args>
|
||||
void Error(std::string codespace, fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (!isInitialized) {
|
||||
template <typename... Args> void Error(std::string codespace, fmt::format_string<Args...> 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>(args)...);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLogger(codespace);
|
||||
log[codespace]->error(fmt, std::forward<Args>(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<std::string, std::shared_ptr<spdlog::logger>> log;
|
||||
std::shared_ptr<interfaces::storage::File> pFile;
|
||||
public:
|
||||
|
||||
public:
|
||||
bool isConstructed = false;
|
||||
bool isInitialized = false;
|
||||
};
|
||||
}
|
||||
} // namespace wd::common
|
||||
@@ -2,15 +2,17 @@
|
||||
// Created by DexrnZacAttack on 1/23/26 using zPc-i2.
|
||||
//
|
||||
#pragma once
|
||||
#include <ctime>
|
||||
#include "Interfaces/Storage/Directory.h"
|
||||
#include "Config.h"
|
||||
#include "Interfaces/Storage/Directory.h"
|
||||
#include "Logging.h"
|
||||
#include "exports.h"
|
||||
#include <ctime>
|
||||
|
||||
namespace wd::common {
|
||||
class WD_API WinDurango {
|
||||
public:
|
||||
namespace wd::common
|
||||
{
|
||||
class WD_API WinDurango
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<WinDurango> GetInstance();
|
||||
|
||||
WinDurango() = default;
|
||||
@@ -21,10 +23,9 @@ namespace wd::common {
|
||||
Config config;
|
||||
Logging log;
|
||||
|
||||
private:
|
||||
private:
|
||||
bool _inited = false;
|
||||
std::shared_ptr<interfaces::storage::Directory> rootDir;
|
||||
std::shared_ptr<interfaces::storage::Directory> WinDurangoRoot;
|
||||
};
|
||||
} // namespace wd::common
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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<typename T>
|
||||
T& wd::common::Config::operator[](std::string node) {
|
||||
template <typename T> T &wd::common::Config::operator[](std::string node)
|
||||
{
|
||||
return data[node];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool wd::common::Config::set(std::string node, T type) {
|
||||
template <typename T> bool wd::common::Config::set(std::string node, T type)
|
||||
{
|
||||
data[node] = type;
|
||||
return true;
|
||||
}
|
||||
@@ -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<spdlog::sinks::stdout_color_sink_mt>();
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(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<spdlog::logger> logg = std::make_shared<spdlog::logger>("WinDurango", spdlog::sinks_init_list{console_sink, file_sink});
|
||||
std::shared_ptr<spdlog::logger> logg =
|
||||
std::make_shared<spdlog::logger>("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<spdlog::sinks::stdout_color_sink_mt>();
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(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<spdlog::logger> logg = std::make_shared<spdlog::logger>(codespace, spdlog::sinks_init_list{console_sink, file_sink});
|
||||
std::shared_ptr<spdlog::logger> logg =
|
||||
std::make_shared<spdlog::logger>(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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,21 +7,26 @@ namespace wd::common
|
||||
{
|
||||
std::shared_ptr<WinDurango> WinDurango::GetInstance()
|
||||
{
|
||||
static std::shared_ptr<WinDurango> Instance = std::make_shared<WinDurango>(); // if we don't declare it in src, it will make multiple instances per
|
||||
// header import in different libs afaik
|
||||
static std::shared_ptr<WinDurango> Instance =
|
||||
std::make_shared<WinDurango>(); // 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<interfaces::storage::Directory> rootDir) {
|
||||
if (this->_inited) {
|
||||
void WinDurango::Init(std::shared_ptr<interfaces::storage::Directory> 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<interfaces::storage::File> LogFile = WinDurangoRoot->CreateFile("windurango_log_" + date + ".log");
|
||||
std::shared_ptr<interfaces::storage::File> LogFile =
|
||||
WinDurangoRoot->CreateFile("windurango_log_" + date + ".log");
|
||||
std::shared_ptr<interfaces::storage::File> 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
#include "d3d11.x.h"
|
||||
|
||||
template<abi_t ABI>
|
||||
class GraphicsUnknown : public xbox::IGraphicsUnknown<ABI>
|
||||
template <abi_t ABI> class GraphicsUnknown : public xbox::IGraphicsUnknown<ABI>
|
||||
{
|
||||
public:
|
||||
public:
|
||||
//
|
||||
// IUnknown
|
||||
//
|
||||
HRESULT QueryInterface(REFIID riid, void** ppvObject);
|
||||
HRESULT QueryInterface(REFIID riid, void **ppvObject);
|
||||
ULONG AddRef();
|
||||
ULONG Release();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
#include <initguid.h>
|
||||
#include <d3d11.h>
|
||||
#include <initguid.h>
|
||||
|
||||
extern const IID IID_IPrivateData;
|
||||
extern const IID IID_IGraphicsUnknown;
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
#pragma once
|
||||
#pragma comment(lib, "d3d11.lib")
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
#pragma comment (lib, "version.lib")
|
||||
#include <d3d11_4.h>
|
||||
#include <dxgi1_6.h>
|
||||
#pragma comment(lib, "version.lib")
|
||||
#include "unknown.g.h"
|
||||
#include "xcom/base.h"
|
||||
#include <Windows.h>
|
||||
#include <bitset>
|
||||
#include <d3d11_4.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <map>
|
||||
#include "unknown.g.h"
|
||||
#include <mutex>
|
||||
|
||||
//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<void*, void*> g_ResourceMap;
|
||||
// Multimap for placement update
|
||||
std::multimap<void *, void *> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,28 +6,23 @@
|
||||
|
||||
namespace xbox
|
||||
{
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnknown;
|
||||
template <abi_t ABI> struct IGraphicsUnknown;
|
||||
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnknownVtbl;
|
||||
template <abi_t ABI> struct IGraphicsUnknownVtbl;
|
||||
|
||||
template<abi_t ABI>
|
||||
struct __declspec(uuid("bcfaae29-e1a2-4b9a-aafc-55b9ff21fa54")) IGraphicsUnwrap;
|
||||
template <abi_t ABI> struct __declspec(uuid("bcfaae29-e1a2-4b9a-aafc-55b9ff21fa54")) IGraphicsUnwrap;
|
||||
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnwrapVtbl;
|
||||
template <abi_t ABI> struct IGraphicsUnwrapVtbl;
|
||||
|
||||
namespace details
|
||||
{
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnknownData
|
||||
template <abi_t ABI> struct IGraphicsUnknownData
|
||||
{
|
||||
ULONG m_RefCount;
|
||||
};
|
||||
|
||||
template<abi_t ABI>
|
||||
requires (ABI >= abi_t{ 10,0,14393,2152 } && ABI < abi_t{ 10,0,19041,3453 })
|
||||
template <abi_t ABI>
|
||||
requires(ABI >= abi_t{10, 0, 14393, 2152} && ABI < abi_t{10, 0, 19041, 3453})
|
||||
struct IGraphicsUnknownData<ABI>
|
||||
{
|
||||
ULONG m_DeviceIndex : 3;
|
||||
@@ -36,8 +31,8 @@ namespace xbox
|
||||
ULONG m_RefCount;
|
||||
};
|
||||
|
||||
template<abi_t ABI>
|
||||
requires (ABI >= abi_t{ 10,0,19041,3453 })
|
||||
template <abi_t ABI>
|
||||
requires(ABI >= abi_t{10, 0, 19041, 3453})
|
||||
struct IGraphicsUnknownData<ABI>
|
||||
{
|
||||
ULONG m_DeviceIndex : 3;
|
||||
@@ -46,41 +41,39 @@ namespace xbox
|
||||
ULONG m_Reserved : 27;
|
||||
ULONG m_RefCount;
|
||||
};
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnknown : details::IGraphicsUnknownData<ABI>
|
||||
template <abi_t ABI> struct IGraphicsUnknown : details::IGraphicsUnknownData<ABI>
|
||||
{
|
||||
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<abi_t ABI>
|
||||
struct IGraphicsUnknownVtbl
|
||||
template <abi_t ABI> 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<abi_t ABI>
|
||||
struct IGraphicsUnwrap
|
||||
template <abi_t ABI> struct IGraphicsUnwrap
|
||||
{
|
||||
};
|
||||
|
||||
template<abi_t ABI>
|
||||
struct IGraphicsUnwrapVtbl
|
||||
template <abi_t ABI> 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__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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<APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, decltype(&::RoUnregisterForApartmentShutdown), ::RoUnregisterForApartmentShutdown>;
|
||||
|
||||
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<APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, decltype(&::RoUnregisterForApartmentShutdown),
|
||||
::RoUnregisterForApartmentShutdown>;
|
||||
|
||||
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<PCWSTR>(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 <typename T>
|
||||
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<T (*)()>(maker)();
|
||||
};
|
||||
inner = reinterpret_cast<void*>(maker);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
any_maker(F&& f)
|
||||
{
|
||||
adapter = [](auto maker) -> std::any {
|
||||
return reinterpret_cast<F*>(maker)[0]();
|
||||
};
|
||||
inner = std::addressof(f);
|
||||
}
|
||||
fail_fast,
|
||||
ignore
|
||||
};
|
||||
|
||||
template <apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast, typename test_hook = apartment_variable_platform>
|
||||
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<PCWSTR>(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<apartment_variable_base<leak_action, test_hook>*, std::any> variables;
|
||||
};
|
||||
|
||||
// Apartment id -> variables storage.
|
||||
inline static wil::object_without_destructor_on_shutdown<std::unordered_map<unsigned long long, apartment_variable_storage>> s_apartmentStorage;
|
||||
|
||||
constexpr apartment_variable_base() = default;
|
||||
~apartment_variable_base()
|
||||
template <typename T> 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<T (*)()>(maker)(); };
|
||||
inner = reinterpret_cast<void *>(maker);
|
||||
}
|
||||
|
||||
template <typename F> any_maker(F &&f)
|
||||
{
|
||||
adapter = [](auto maker) -> std::any { return reinterpret_cast<F *>(maker)[0](); };
|
||||
inner = std::addressof(f);
|
||||
}
|
||||
};
|
||||
|
||||
template <apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
|
||||
typename test_hook = apartment_variable_platform>
|
||||
struct apartment_variable_base
|
||||
{
|
||||
inline static winrt::slim_mutex s_lock;
|
||||
|
||||
struct apartment_variable_storage
|
||||
{
|
||||
apartment_variable_storage(apartment_variable_storage &&other) noexcept = default;
|
||||
apartment_variable_storage(const apartment_variable_storage &other) = delete;
|
||||
|
||||
apartment_variable_storage(typename test_hook::shutdown_type &&cookie_) : cookie(std::move(cookie_))
|
||||
{
|
||||
// If you hit this fail fast it means the storage in s_apartmentStorage will be leaked.
|
||||
// For apartment variables used in .exes, this is expected and
|
||||
// this fail fast should be disabled using
|
||||
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
|
||||
//
|
||||
// For DLLs, if this is expected, disable this fail fast using
|
||||
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
|
||||
//
|
||||
// Use of apartment variables in DLLs only loaded by COM will never hit this case
|
||||
// as COM will unload DLLs before apartments are rundown,
|
||||
// providing the opportunity to empty s_apartmentStorage.
|
||||
//
|
||||
// But DLLs loaded and unloaded to call DLL entry points (outside of COM) may
|
||||
// create variable storage that can't be cleaned up as the DLL lifetime is
|
||||
// shorter that the COM lifetime. In these cases either
|
||||
// 1) accept the leaks and disable the fail fast as describe above
|
||||
// 2) disable module unloading by calling wil::ensure_module_stays_loaded
|
||||
// 3) CoCreate an object from this DLL to make COM aware of the DLL
|
||||
FAIL_FAST_IF(!s_apartmentStorage.get().empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non-copyable, non-assignable
|
||||
apartment_variable_base(apartment_variable_base const&) = delete;
|
||||
void operator=(apartment_variable_base const&) = delete;
|
||||
|
||||
// get current value or throw if no value has been set
|
||||
std::any& get_existing()
|
||||
{
|
||||
auto any = get_if();
|
||||
if (!any)
|
||||
{
|
||||
THROW_HR(E_NOT_SET);
|
||||
}
|
||||
|
||||
return *any;
|
||||
}
|
||||
|
||||
static apartment_variable_storage* get_current_apartment_variable_storage()
|
||||
{
|
||||
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
|
||||
if (storage != s_apartmentStorage.get().end())
|
||||
{
|
||||
return &storage->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
apartment_variable_storage* ensure_current_apartment_variables()
|
||||
{
|
||||
auto variables = get_current_apartment_variable_storage();
|
||||
if (variables)
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
struct ApartmentObserver : public winrt::implements<ApartmentObserver, IApartmentShutdown>
|
||||
{
|
||||
void STDMETHODCALLTYPE OnUninitialize(unsigned long long apartmentId) noexcept override
|
||||
{
|
||||
// This code runs at apartment rundown so be careful to avoid deadlocks by
|
||||
// extracting the variables under the lock then release them outside.
|
||||
auto variables = [apartmentId]() {
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
return s_apartmentStorage.get().extract(apartmentId);
|
||||
}();
|
||||
WI_ASSERT(variables.key() == apartmentId);
|
||||
// The system implicitly releases the shutdown observer
|
||||
// after invoking the callback and does not allow calling unregister
|
||||
// in the callback. So release the reference to the registration.
|
||||
variables.mapped().cookie.release();
|
||||
}
|
||||
winrt::apartment_context context;
|
||||
typename test_hook::shutdown_type cookie;
|
||||
// Variables are stored using the address of the apartment_variable_base<> as the key.
|
||||
std::unordered_map<apartment_variable_base<leak_action, test_hook> *, std::any> variables;
|
||||
};
|
||||
auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().get());
|
||||
return &s_apartmentStorage.get()
|
||||
.insert({test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration))})
|
||||
.first->second;
|
||||
|
||||
// Apartment id -> variables storage.
|
||||
inline static wil::object_without_destructor_on_shutdown<
|
||||
std::unordered_map<unsigned long long, apartment_variable_storage>>
|
||||
s_apartmentStorage;
|
||||
|
||||
constexpr apartment_variable_base() = default;
|
||||
~apartment_variable_base()
|
||||
{
|
||||
// Global variables (object with static storage duration)
|
||||
// are run down when the process is shutting down or when the
|
||||
// dll is unloaded. At these points it is not possible to start
|
||||
// an async operation and the work performed is not needed,
|
||||
// the apartments with variable have been run down already.
|
||||
const auto isGlobal = details::IsGlobalVariable(this);
|
||||
if (!isGlobal)
|
||||
{
|
||||
clear_all_apartments_async();
|
||||
}
|
||||
|
||||
if constexpr (leak_action == apartment_variable_leak_action::fail_fast)
|
||||
{
|
||||
if (isGlobal && !ProcessShutdownInProgress())
|
||||
{
|
||||
// If you hit this fail fast it means the storage in s_apartmentStorage will be leaked.
|
||||
// For apartment variables used in .exes, this is expected and
|
||||
// this fail fast should be disabled using
|
||||
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
|
||||
//
|
||||
// For DLLs, if this is expected, disable this fail fast using
|
||||
// wil::apartment_variable<T, wil::apartment_variable_leak_action::ignore>
|
||||
//
|
||||
// Use of apartment variables in DLLs only loaded by COM will never hit this case
|
||||
// as COM will unload DLLs before apartments are rundown,
|
||||
// providing the opportunity to empty s_apartmentStorage.
|
||||
//
|
||||
// But DLLs loaded and unloaded to call DLL entry points (outside of COM) may
|
||||
// create variable storage that can't be cleaned up as the DLL lifetime is
|
||||
// shorter that the COM lifetime. In these cases either
|
||||
// 1) accept the leaks and disable the fail fast as describe above
|
||||
// 2) disable module unloading by calling wil::ensure_module_stays_loaded
|
||||
// 3) CoCreate an object from this DLL to make COM aware of the DLL
|
||||
FAIL_FAST_IF(!s_apartmentStorage.get().empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// non-copyable, non-assignable
|
||||
apartment_variable_base(apartment_variable_base const &) = delete;
|
||||
void operator=(apartment_variable_base const &) = delete;
|
||||
|
||||
// get current value or throw if no value has been set
|
||||
std::any &get_existing()
|
||||
{
|
||||
auto any = get_if();
|
||||
if (!any)
|
||||
{
|
||||
THROW_HR(E_NOT_SET);
|
||||
}
|
||||
|
||||
return *any;
|
||||
}
|
||||
|
||||
static apartment_variable_storage *get_current_apartment_variable_storage()
|
||||
{
|
||||
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
|
||||
if (storage != s_apartmentStorage.get().end())
|
||||
{
|
||||
return &storage->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
apartment_variable_storage *ensure_current_apartment_variables()
|
||||
{
|
||||
auto variables = get_current_apartment_variable_storage();
|
||||
if (variables)
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
struct ApartmentObserver : public winrt::implements<ApartmentObserver, IApartmentShutdown>
|
||||
{
|
||||
void STDMETHODCALLTYPE OnUninitialize(unsigned long long apartmentId) noexcept override
|
||||
{
|
||||
// This code runs at apartment rundown so be careful to avoid deadlocks by
|
||||
// extracting the variables under the lock then release them outside.
|
||||
auto variables = [apartmentId]() {
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
return s_apartmentStorage.get().extract(apartmentId);
|
||||
}();
|
||||
WI_ASSERT(variables.key() == apartmentId);
|
||||
// The system implicitly releases the shutdown observer
|
||||
// after invoking the callback and does not allow calling unregister
|
||||
// in the callback. So release the reference to the registration.
|
||||
variables.mapped().cookie.release();
|
||||
}
|
||||
};
|
||||
auto shutdownRegistration =
|
||||
test_hook::RegisterForApartmentShutdown(winrt::make<ApartmentObserver>().get());
|
||||
return &s_apartmentStorage.get()
|
||||
.insert({test_hook::GetApartmentId(),
|
||||
apartment_variable_storage(std::move(shutdownRegistration))})
|
||||
.first->second;
|
||||
}
|
||||
|
||||
// get current value or custom-construct one on demand
|
||||
template <typename T> std::any &get_or_create(any_maker<T> &&creator)
|
||||
{
|
||||
apartment_variable_storage *variable_storage = nullptr;
|
||||
|
||||
{ // scope for lock
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
variable_storage = ensure_current_apartment_variables();
|
||||
|
||||
auto variable = variable_storage->variables.find(this);
|
||||
if (variable != variable_storage->variables.end())
|
||||
{
|
||||
return variable->second;
|
||||
}
|
||||
} // drop the lock
|
||||
|
||||
// create the object outside the lock to avoid reentrant deadlock
|
||||
auto value = creator();
|
||||
|
||||
auto insert_lock = winrt::slim_lock_guard(s_lock);
|
||||
// The insertion may fail if creator() recursively caused itself to be created,
|
||||
// in which case we return the existing object and the falsely-created one is discarded.
|
||||
return variable_storage->variables.insert({this, std::move(value)}).first->second;
|
||||
}
|
||||
|
||||
// get pointer to current value or nullptr if no value has been set
|
||||
std::any *get_if()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
auto variable = variable_storage->variables.find(this);
|
||||
if (variable != variable_storage->variables.end())
|
||||
{
|
||||
return &(variable->second);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// replace or create the current value, fail fasts if the value is not already stored
|
||||
void set(std::any value)
|
||||
{
|
||||
// release value, with the swapped value, outside of the lock
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId());
|
||||
FAIL_FAST_IF(storage == s_apartmentStorage.get().end());
|
||||
auto &variable_storage = storage->second;
|
||||
auto variable = variable_storage.variables.find(this);
|
||||
FAIL_FAST_IF(variable == variable_storage.variables.end());
|
||||
variable->second.swap(value);
|
||||
}
|
||||
}
|
||||
|
||||
// remove any current value
|
||||
void clear()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
variable_storage->variables.erase(this);
|
||||
if (variable_storage->variables.size() == 0)
|
||||
{
|
||||
s_apartmentStorage.get().erase(test_hook::GetApartmentId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async()
|
||||
{
|
||||
// gather all the apartments that hold objects we need to destruct
|
||||
// (do not gather the objects themselves, because the apartment might
|
||||
// destruct before we get around to it, and we should let the apartment
|
||||
// destruct the object while it still can).
|
||||
|
||||
std::vector<winrt::apartment_context> contexts;
|
||||
{ // scope for lock
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
for (auto &[id, storage] : s_apartmentStorage.get())
|
||||
{
|
||||
auto variable = storage.variables.find(this);
|
||||
if (variable != storage.variables.end())
|
||||
{
|
||||
contexts.push_back(storage.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contexts.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup
|
||||
FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put()));
|
||||
|
||||
// From a background thread hop into each apartment to run down the object
|
||||
// if it's still there.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// This hook enables testing the case where execution of this method loses the race with
|
||||
// apartment rundown by other means.
|
||||
if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE)
|
||||
{
|
||||
Sleep(test_hook::AsyncRundownDelayForTestingRaces);
|
||||
}
|
||||
|
||||
for (auto &&context : contexts)
|
||||
{
|
||||
try
|
||||
{
|
||||
co_await context;
|
||||
clear();
|
||||
}
|
||||
catch (winrt::hresult_error const &e)
|
||||
{
|
||||
// Ignore failure if apartment ran down before we could clean it up.
|
||||
// The object already ran down as part of apartment cleanup.
|
||||
if ((e.code() != RPC_E_SERVER_DIED_DNE) && (e.code() != RPC_E_DISCONNECTED))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FAIL_FAST();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const auto &storage()
|
||||
{
|
||||
return s_apartmentStorage.get();
|
||||
}
|
||||
|
||||
static size_t current_apartment_variable_count()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
return variable_storage->variables.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
// Apartment variables enable storing COM objects safely in globals
|
||||
// (objects with static storage duration) by creating a unique copy
|
||||
// in each apartment and managing their lifetime based on apartment rundown
|
||||
// notifications.
|
||||
// They can also be used for automatic or dynamic storage duration but those
|
||||
// cases are less common.
|
||||
// This type is also useful for storing references to apartment affine objects.
|
||||
//
|
||||
// Note, that apartment variables hosted in a COM DLL need to integrate with
|
||||
// the DllCanUnloadNow() function to include the ref counts contributed by
|
||||
// C++ WinRT objects. This is automatic for DLLs that host C++ WinRT objects
|
||||
// but WRL projects will need to be updated to call winrt::get_module_lock().
|
||||
|
||||
template <typename T, apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast,
|
||||
typename test_hook = wil::apartment_variable_platform>
|
||||
struct apartment_variable : details::apartment_variable_base<leak_action, test_hook>
|
||||
{
|
||||
using base = details::apartment_variable_base<leak_action, test_hook>;
|
||||
|
||||
constexpr apartment_variable() = default;
|
||||
|
||||
// Get current value or throw if no value has been set.
|
||||
T &get_existing()
|
||||
{
|
||||
return std::any_cast<T &>(base::get_existing());
|
||||
}
|
||||
|
||||
// get current value or custom-construct one on demand
|
||||
template <typename T>
|
||||
std::any& get_or_create(any_maker<T>&& creator)
|
||||
// Get current value or default-construct one on demand.
|
||||
T &get_or_create()
|
||||
{
|
||||
apartment_variable_storage* variable_storage = nullptr;
|
||||
return std::any_cast<T &>(base::get_or_create(details::any_maker<T>()));
|
||||
}
|
||||
|
||||
{ // 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 <typename F> T &get_or_create(F &&f)
|
||||
{
|
||||
return std::any_cast<T &>(base::get_or_create(details::any_maker<T>(std::forward<F>(f))));
|
||||
}
|
||||
|
||||
// get pointer to current value or nullptr if no value has been set
|
||||
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<T>(base::get_if());
|
||||
}
|
||||
|
||||
// replace or create the current value, fail fasts if the value is not already stored
|
||||
void set(std::any value)
|
||||
template <typename V> 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<V>(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<winrt::apartment_context> contexts;
|
||||
{ // scope for lock
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
for (auto& [id, storage] : s_apartmentStorage.get())
|
||||
{
|
||||
auto variable = storage.variables.find(this);
|
||||
if (variable != storage.variables.end())
|
||||
{
|
||||
contexts.push_back(storage.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contexts.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup
|
||||
FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put()));
|
||||
|
||||
// From a background thread hop into each apartment to run down the object
|
||||
// if it's still there.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// This hook enables testing the case where execution of this method loses the race with
|
||||
// apartment rundown by other means.
|
||||
if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE)
|
||||
{
|
||||
Sleep(test_hook::AsyncRundownDelayForTestingRaces);
|
||||
}
|
||||
|
||||
for (auto&& context : contexts)
|
||||
{
|
||||
try
|
||||
{
|
||||
co_await context;
|
||||
clear();
|
||||
}
|
||||
catch (winrt::hresult_error const& e)
|
||||
{
|
||||
// Ignore failure if apartment ran down before we could clean it up.
|
||||
// The object already ran down as part of apartment cleanup.
|
||||
if ((e.code() != RPC_E_SERVER_DIED_DNE) && (e.code() != RPC_E_DISCONNECTED))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FAIL_FAST();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const auto& storage()
|
||||
{
|
||||
return s_apartmentStorage.get();
|
||||
}
|
||||
|
||||
static size_t current_apartment_variable_count()
|
||||
{
|
||||
auto lock = winrt::slim_lock_guard(s_lock);
|
||||
if (auto variable_storage = get_current_apartment_variable_storage())
|
||||
{
|
||||
return variable_storage->variables.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// 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 <typename T, apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast, typename test_hook = wil::apartment_variable_platform>
|
||||
struct apartment_variable : details::apartment_variable_base<leak_action, test_hook>
|
||||
{
|
||||
using base = details::apartment_variable_base<leak_action, test_hook>;
|
||||
|
||||
constexpr apartment_variable() = default;
|
||||
|
||||
// Get current value or throw if no value has been set.
|
||||
T& get_existing()
|
||||
{
|
||||
return std::any_cast<T&>(base::get_existing());
|
||||
}
|
||||
|
||||
// Get current value or default-construct one on demand.
|
||||
T& get_or_create()
|
||||
{
|
||||
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>()));
|
||||
}
|
||||
|
||||
// Get current value or custom-construct one on demand.
|
||||
template <typename F>
|
||||
T& get_or_create(F&& f)
|
||||
{
|
||||
return std::any_cast<T&>(base::get_or_create(details::any_maker<T>(std::forward<F>(f))));
|
||||
}
|
||||
|
||||
// get pointer to current value or nullptr if no value has been set
|
||||
T* get_if()
|
||||
{
|
||||
return std::any_cast<T>(base::get_if());
|
||||
}
|
||||
|
||||
// replace or create the current value, fail fasts if the value is not already stored
|
||||
template <typename V>
|
||||
void set(V&& value)
|
||||
{
|
||||
return base::set(std::forward<V>(value));
|
||||
}
|
||||
|
||||
// Clear the value in the current apartment.
|
||||
using base::clear;
|
||||
|
||||
// Asynchronously clear the value in all apartments it is present in.
|
||||
using base::clear_all_apartments_async;
|
||||
|
||||
// For testing only.
|
||||
// 1) To observe the state of the storage in the debugger assign this to
|
||||
// a temporary variable (const&) and watch its contents.
|
||||
// 2) Use this to test the implementation.
|
||||
using base::storage;
|
||||
// For testing only. The number of variables in the current apartment.
|
||||
using base::current_apartment_variable_count;
|
||||
};
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_COM_APARTMENT_VARIABLE_INCLUDED
|
||||
|
||||
@@ -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<wistd::is_class<ptrType>::value, void*> = nullptr
|
||||
#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void*> = nullptr
|
||||
#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t<wistd::is_class<ptrType>::value, void *> = nullptr
|
||||
#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t<!wistd::is_class<ptrType>::value, void *> = nullptr
|
||||
|
||||
// Uses the __has_include macro, if available. Otherwise uses a user-provided fallback. E.g. the fallback could always
|
||||
// default to true or false, or it could do something like a C++ standard version check
|
||||
@@ -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<decltype(val)>>(val)
|
||||
//! Validates that exactly ONE bit is set in compile-time constant `flag`
|
||||
#define WI_StaticAssertSingleBitSet(flag) \
|
||||
static_cast<decltype(flag)>(::wil::details::verify_single_flag_helper<static_cast<unsigned long long>(WI_EnumValue(flag))>::value)
|
||||
#define WI_StaticAssertSingleBitSet(flag) \
|
||||
static_cast<decltype(flag)>( \
|
||||
::wil::details::verify_single_flag_helper<static_cast<unsigned long long>(WI_EnumValue(flag))>::value)
|
||||
|
||||
//! @name Bitwise manipulation macros
|
||||
//! @{
|
||||
@@ -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<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast<decltype((val) & (flags))>(0))
|
||||
#define WI_IsAnyFlagSet(val, flags) \
|
||||
(static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) != \
|
||||
static_cast<decltype((val) & (flags))>(0))
|
||||
//! Evaluates as true if a single compile-time constant `flag` is set within `val`.
|
||||
#define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag))
|
||||
|
||||
//! Evaluates as true if every bitflag specified in `flags` is clear within `val`.
|
||||
#define WI_AreAllFlagsClear(val, flags) \
|
||||
(static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast<decltype((val) & (flags))>(0))
|
||||
#define WI_AreAllFlagsClear(val, flags) \
|
||||
(static_cast<decltype((val) & (flags))>(WI_EnumValue(val) & WI_EnumValue(flags)) == \
|
||||
static_cast<decltype((val) & (flags))>(0))
|
||||
//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`.
|
||||
#define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags))
|
||||
//! Evaluates as true if a single compile-time constant `flag` is clear within `val`.
|
||||
@@ -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<unsigned char>(fn()); \
|
||||
} \
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
|
||||
extern "C" \
|
||||
{ \
|
||||
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
|
||||
} \
|
||||
__pragma(comment(linker, "/INCLUDE:_g_header_init_" #name))
|
||||
#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
|
||||
extern "C" \
|
||||
{ \
|
||||
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
|
||||
} \
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
|
||||
extern "C" \
|
||||
{ \
|
||||
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
|
||||
} \
|
||||
__pragma(comment(linker, "/INCLUDE:g_header_init_" #name))
|
||||
#else
|
||||
#error linker pragma must include g_header_init variation
|
||||
@@ -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 <typename T>
|
||||
class pointer_range
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
public:
|
||||
pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_)
|
||||
template <typename T> 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 <typename T>
|
||||
details::pointer_range<T> make_range(T begin, T end)
|
||||
{
|
||||
return details::pointer_range<T>(begin, end);
|
||||
}
|
||||
|
||||
/** Enables using range-based for on a range when given the base pointer and the number of objects in the range.
|
||||
~~~~
|
||||
for (auto& obj : make_range(objPointer, objCount)) { }
|
||||
~~~~ */
|
||||
template <typename T>
|
||||
details::pointer_range<T> make_range(T begin, size_t count)
|
||||
{
|
||||
return details::pointer_range<T>(begin, begin + count);
|
||||
}
|
||||
|
||||
//! @defgroup outparam Output Parameters
|
||||
//! Improve the conciseness of assigning values to optional output parameters.
|
||||
//! @{
|
||||
|
||||
/** Assign the given value to an optional output parameter.
|
||||
Makes code more concise by removing trivial `if (outParam)` blocks. */
|
||||
template <typename T>
|
||||
inline void assign_to_opt_param(_Out_opt_ T* outParam, T val)
|
||||
{
|
||||
if (outParam != nullptr)
|
||||
/** Enables using range-based for between a begin and end object pointer.
|
||||
~~~~
|
||||
for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { }
|
||||
~~~~ */
|
||||
template <typename T> details::pointer_range<T> make_range(T begin, T end)
|
||||
{
|
||||
*outParam = val;
|
||||
return details::pointer_range<T>(begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
/** Assign NULL to an optional output pointer parameter.
|
||||
Makes code more concise by removing trivial `if (outParam)` blocks. */
|
||||
template <typename T>
|
||||
inline void assign_null_to_opt_param(_Out_opt_ T* outParam)
|
||||
{
|
||||
if (outParam != nullptr)
|
||||
/** Enables using range-based for on a range when given the base pointer and the number of objects in the range.
|
||||
~~~~
|
||||
for (auto& obj : make_range(objPointer, objCount)) { }
|
||||
~~~~ */
|
||||
template <typename T> details::pointer_range<T> make_range(T begin, size_t count)
|
||||
{
|
||||
*outParam = nullptr;
|
||||
return details::pointer_range<T>(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 <unsigned int... Rest>
|
||||
struct FeatureRequiredBy
|
||||
{
|
||||
static const bool enabled = wil::variadic_logical_or<WilFeature<Rest>::enabled...>::value;
|
||||
};
|
||||
~~~~ */
|
||||
template <bool...>
|
||||
struct variadic_logical_or;
|
||||
/// @cond
|
||||
template <>
|
||||
struct variadic_logical_or<> : wistd::false_type
|
||||
{
|
||||
};
|
||||
template <bool... Rest>
|
||||
struct variadic_logical_or<true, Rest...> : wistd::true_type
|
||||
{
|
||||
};
|
||||
template <bool... Rest>
|
||||
struct variadic_logical_or<false, Rest...> : variadic_logical_or<Rest...>::type
|
||||
{
|
||||
};
|
||||
/// @endcond
|
||||
//! @defgroup outparam Output Parameters
|
||||
//! Improve the conciseness of assigning values to optional output parameters.
|
||||
//! @{
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <unsigned long long flag>
|
||||
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 <typename T> 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 <typename T> inline void assign_null_to_opt_param(_Out_opt_ T *outParam)
|
||||
{
|
||||
if (outParam != nullptr)
|
||||
{
|
||||
*outParam = nullptr;
|
||||
}
|
||||
}
|
||||
//! @} // end output parameter helpers
|
||||
|
||||
/** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean
|
||||
evaluation. Example usage:
|
||||
~~~~
|
||||
template <unsigned int... Rest>
|
||||
struct FeatureRequiredBy
|
||||
{
|
||||
static const bool enabled = wil::variadic_logical_or<WilFeature<Rest>::enabled...>::value;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
~~~~ */
|
||||
template <bool...> struct variadic_logical_or;
|
||||
/// @cond
|
||||
template <> struct variadic_logical_or<> : wistd::false_type
|
||||
{
|
||||
};
|
||||
template <bool... Rest> struct variadic_logical_or<true, Rest...> : wistd::true_type
|
||||
{
|
||||
};
|
||||
template <bool... Rest> struct variadic_logical_or<false, Rest...> : variadic_logical_or<Rest...>::type
|
||||
{
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
//! @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 <unsigned long long flag> struct verify_single_flag_helper
|
||||
{
|
||||
static_assert((flag != 0) && ((flag & (flag - 1)) == 0),
|
||||
"Single flag expected, zero or multiple flags found");
|
||||
static const unsigned long long value = flag;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/** Verify that `val` can be evaluated as a logical bool.
|
||||
Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL,
|
||||
boolean, BOOLEAN, and classes with an explicit bool cast.
|
||||
@param val The logical bool expression
|
||||
@return A C++ bool representing the evaluation of `val`. */
|
||||
template <typename T, __R_ENABLE_IF_IS_CLASS(T)>
|
||||
_Post_satisfies_(return == static_cast<bool>(val)) inline constexpr bool verify_bool(const T& val) WI_NOEXCEPT
|
||||
{
|
||||
return static_cast<bool>(val);
|
||||
}
|
||||
//! @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 <typename T, __R_ENABLE_IF_IS_NOT_CLASS(T)>
|
||||
inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(!wistd::is_same<T, T>::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
|
||||
return false;
|
||||
}
|
||||
/** Verify that `val` can be evaluated as a logical bool.
|
||||
Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL,
|
||||
boolean, BOOLEAN, and classes with an explicit bool cast.
|
||||
@param val The logical bool expression
|
||||
@return A C++ bool representing the evaluation of `val`. */
|
||||
template <typename T, __R_ENABLE_IF_IS_CLASS(T)>
|
||||
_Post_satisfies_(return == static_cast<bool>(val)) inline constexpr bool verify_bool(const T &val) WI_NOEXCEPT
|
||||
{
|
||||
return static_cast<bool>(val);
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == val) inline constexpr bool verify_bool<bool>(bool val) WI_NOEXCEPT
|
||||
{
|
||||
return val;
|
||||
}
|
||||
template <typename T, __R_ENABLE_IF_IS_NOT_CLASS(T)> inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(!wistd::is_same<T, T>::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<int>(int val) WI_NOEXCEPT
|
||||
{
|
||||
return (val != 0);
|
||||
}
|
||||
template <> _Post_satisfies_(return == val) inline constexpr bool verify_bool<bool>(bool val) WI_NOEXCEPT
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<unsigned char>(unsigned char val) WI_NOEXCEPT
|
||||
{
|
||||
return (val != 0);
|
||||
}
|
||||
template <> _Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<int>(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 <typename T>
|
||||
_Post_satisfies_(return == val) inline constexpr int verify_BOOL(T val) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL;
|
||||
static_assert((wistd::is_same<T, int>::value), "Wrong Type: BOOL expected");
|
||||
return val;
|
||||
}
|
||||
template <>
|
||||
_Post_satisfies_(return ==
|
||||
(val != 0)) inline constexpr bool verify_bool<unsigned char>(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 <typename T> _Post_satisfies_(return == val) inline constexpr int verify_BOOL(T val) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL;
|
||||
static_assert((wistd::is_same<T, int>::value), "Wrong Type: BOOL expected");
|
||||
return val;
|
||||
}
|
||||
|
||||
Note that occasionally you might run into an HRESULT which is directly defined with a `#define`, such as:
|
||||
~~~~
|
||||
#define UIA_E_NOTSUPPORTED 0x80040204
|
||||
~~~~
|
||||
Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When
|
||||
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change
|
||||
their definition to match the manner in which `HRESULT` constants are defined in winerror.h:
|
||||
~~~~
|
||||
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
|
||||
~~~~
|
||||
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
|
||||
to use this value in a macro that utilizes `verify_hresult`, for example:
|
||||
~~~~
|
||||
RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
|
||||
~~~~
|
||||
@param hr The HRESULT returning expression
|
||||
@return An HRESULT representing the evaluation of `val`. */
|
||||
template <typename T>
|
||||
_Post_satisfies_(return == hr) inline constexpr long verify_hresult(T hr) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT
|
||||
static_assert(wistd::is_same<T, long>::value, "Wrong Type: HRESULT expected");
|
||||
return hr;
|
||||
}
|
||||
/** Verify that `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<NTSTATUS>(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0));
|
||||
@endcode
|
||||
@param status The NTSTATUS returning expression
|
||||
@return An NTSTATUS representing the evaluation of `val`. */
|
||||
template <typename T>
|
||||
_Post_satisfies_(return == status) inline long verify_ntstatus(T status) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long NTSTATUS
|
||||
static_assert(wistd::is_same<T, long>::value, "Wrong Type: NTSTATUS expected");
|
||||
return status;
|
||||
}
|
||||
Note that occasionally you might run into an HRESULT which is directly defined with a `#define`, such as:
|
||||
~~~~
|
||||
#define UIA_E_NOTSUPPORTED 0x80040204
|
||||
~~~~
|
||||
Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When
|
||||
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should
|
||||
change their definition to match the manner in which `HRESULT` constants are defined in winerror.h:
|
||||
~~~~
|
||||
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
|
||||
~~~~
|
||||
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
|
||||
to use this value in a macro that utilizes `verify_hresult`, for example:
|
||||
~~~~
|
||||
RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId));
|
||||
~~~~
|
||||
@param hr The HRESULT returning expression
|
||||
@return An HRESULT representing the evaluation of `val`. */
|
||||
template <typename T> _Post_satisfies_(return == hr) inline constexpr long verify_hresult(T hr) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long
|
||||
// HRESULT
|
||||
static_assert(wistd::is_same<T, long>::value, "Wrong Type: HRESULT expected");
|
||||
return hr;
|
||||
}
|
||||
|
||||
/** Verify that `error` is a Win32 error code.
|
||||
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
|
||||
the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type
|
||||
commonly used when manipulating Win32 error codes.
|
||||
@param error The Win32 error code returning expression
|
||||
@return An Win32 error code representing the evaluation of `error`. */
|
||||
template <typename T>
|
||||
_Post_satisfies_(return == error) inline T verify_win32(T error) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned
|
||||
// long). This accept both types.
|
||||
static_assert(
|
||||
wistd::is_same<T, long>::value || wistd::is_same<T, unsigned long>::value,
|
||||
"Wrong Type: Win32 error code (long / unsigned long) expected");
|
||||
return error;
|
||||
}
|
||||
/// @} // end type validation routines
|
||||
/** Verify that `status` is an NTSTATUS value.
|
||||
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
|
||||
the underlying typedef behind NTSTATUS.
|
||||
//!
|
||||
Note that occasionally you might run into an NTSTATUS which is directly defined with a `#define`, such as:
|
||||
@code
|
||||
#define STATUS_NOT_SUPPORTED 0x1
|
||||
@endcode
|
||||
Though this looks like an `NTSTATUS`, this is actually an `unsigned long` (the hex specification forces this). When
|
||||
these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should
|
||||
change their definition to match the manner in which `NTSTATUS` constants are defined in ntstatus.h:
|
||||
@code
|
||||
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
|
||||
@endcode
|
||||
When these are encountered in the public SDK, their type should not be changed and you should use a static_cast
|
||||
to use this value in a macro that utilizes `verify_ntstatus`, for example:
|
||||
@code
|
||||
NT_RETURN_IF_FALSE(static_cast<NTSTATUS>(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0));
|
||||
@endcode
|
||||
@param status The NTSTATUS returning expression
|
||||
@return An NTSTATUS representing the evaluation of `val`. */
|
||||
template <typename T> _Post_satisfies_(return == status) inline long verify_ntstatus(T status) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long
|
||||
// NTSTATUS
|
||||
static_assert(wistd::is_same<T, long>::value, "Wrong Type: NTSTATUS expected");
|
||||
return status;
|
||||
}
|
||||
|
||||
/// @cond
|
||||
// Implementation details for macros and helper functions... do not use directly.
|
||||
namespace details
|
||||
{
|
||||
// Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value
|
||||
#define __WI_MAKE_UNSIGNED(val) \
|
||||
(__pragma(warning(push)) __pragma(warning(disable : 4310 4309))( \
|
||||
sizeof(val) == 1 ? static_cast<unsigned char>(val) \
|
||||
: sizeof(val) == 2 ? static_cast<unsigned short>(val) \
|
||||
: sizeof(val) == 4 ? static_cast<unsigned long>(val) \
|
||||
/** Verify that `error` is a Win32 error code.
|
||||
Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is
|
||||
the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the
|
||||
type commonly used when manipulating Win32 error codes.
|
||||
@param error The Win32 error code returning expression
|
||||
@return An Win32 error code representing the evaluation of `error`. */
|
||||
template <typename T> _Post_satisfies_(return == error) inline T verify_win32(T error) WI_NOEXCEPT
|
||||
{
|
||||
// Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as
|
||||
// DWORD (unsigned long). This accept both types.
|
||||
static_assert(wistd::is_same<T, long>::value || wistd::is_same<T, unsigned long>::value,
|
||||
"Wrong Type: Win32 error code (long / unsigned long) expected");
|
||||
return error;
|
||||
}
|
||||
/// @} // end type validation routines
|
||||
|
||||
/// @cond
|
||||
// Implementation details for macros and helper functions... do not use directly.
|
||||
namespace details
|
||||
{
|
||||
// Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value
|
||||
#define __WI_MAKE_UNSIGNED(val) \
|
||||
(__pragma(warning(push)) __pragma(warning(disable : 4310 4309))( \
|
||||
sizeof(val) == 1 ? static_cast<unsigned char>(val) \
|
||||
: sizeof(val) == 2 ? static_cast<unsigned short>(val) \
|
||||
: sizeof(val) == 4 ? static_cast<unsigned long>(val) \
|
||||
: static_cast<unsigned long long>(val)) __pragma(warning(pop)))
|
||||
#define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1)))
|
||||
#define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val))
|
||||
|
||||
template <typename TVal, typename TFlags>
|
||||
__forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags)
|
||||
{
|
||||
return ((val & flags) == static_cast<decltype(val & flags)>(flags));
|
||||
}
|
||||
template <typename TVal, typename TFlags>
|
||||
__forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags)
|
||||
{
|
||||
return ((val & flags) == static_cast<decltype(val & flags)>(flags));
|
||||
}
|
||||
|
||||
template <typename TVal>
|
||||
__forceinline constexpr bool IsSingleFlagSetHelper(TVal val)
|
||||
{
|
||||
return __WI_IS_SINGLE_FLAG_SET(val);
|
||||
}
|
||||
template <typename TVal> __forceinline constexpr bool IsSingleFlagSetHelper(TVal val)
|
||||
{
|
||||
return __WI_IS_SINGLE_FLAG_SET(val);
|
||||
}
|
||||
|
||||
template <typename TVal>
|
||||
__forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val)
|
||||
{
|
||||
return ((val == static_cast<wistd::remove_reference_t<TVal>>(0)) || IsSingleFlagSetHelper(val));
|
||||
}
|
||||
template <typename TVal> __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val)
|
||||
{
|
||||
return ((val == static_cast<wistd::remove_reference_t<TVal>>(0)) || IsSingleFlagSetHelper(val));
|
||||
}
|
||||
|
||||
template <typename TVal, typename TMask, typename TFlags>
|
||||
__forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags)
|
||||
{
|
||||
val = static_cast<wistd::remove_reference_t<TVal>>((val & ~mask) | (flags & mask));
|
||||
}
|
||||
template <typename TVal, typename TMask, typename TFlags>
|
||||
__forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal &val, TMask mask, TFlags flags)
|
||||
{
|
||||
val = static_cast<wistd::remove_reference_t<TVal>>((val & ~mask) | (flags & mask));
|
||||
}
|
||||
|
||||
template <long>
|
||||
struct variable_size;
|
||||
template <long> 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 <typename T>
|
||||
struct variable_size_mapping
|
||||
{
|
||||
using type = typename variable_size<sizeof(T)>::type;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
template <typename T> struct variable_size_mapping
|
||||
{
|
||||
using type = typename variable_size<sizeof(T)>::type;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type.
|
||||
This allows code to generically convert any enum class to it's corresponding underlying type. */
|
||||
template <typename T>
|
||||
using integral_from_enum = typename details::variable_size_mapping<T>::type;
|
||||
/** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type.
|
||||
This allows code to generically convert any enum class to it's corresponding underlying type. */
|
||||
template <typename T> using integral_from_enum = typename details::variable_size_mapping<T>::type;
|
||||
|
||||
//! Declares a name that intentionally hides a name from an outer scope.
|
||||
//! Use this to prevent accidental use of a parameter or lambda captured variable.
|
||||
using hide_name = void(struct hidden_name);
|
||||
//! 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)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,10 +14,10 @@
|
||||
#define __WIL_CPPWINRT_INCLUDED
|
||||
|
||||
#include "common.h"
|
||||
#include <windows.h>
|
||||
#include <unknwn.h>
|
||||
#include <inspectable.h>
|
||||
#include <hstring.h>
|
||||
#include <inspectable.h>
|
||||
#include <unknwn.h>
|
||||
#include <windows.h>
|
||||
|
||||
// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to
|
||||
// understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to
|
||||
@@ -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 <winrt/base.h>
|
||||
|
||||
#if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE
|
||||
static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, "C++/WinRT external catch clause already defined outside of WIL");
|
||||
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<std::int32_t>(
|
||||
details::ReportFailure_CaughtException<FailureType::Return>(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress)));
|
||||
}
|
||||
|
||||
inline void __stdcall winrt_throw_hresult(
|
||||
uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
|
||||
{
|
||||
void* callerReturnAddress{nullptr};
|
||||
PCSTR code{nullptr};
|
||||
wil::details::ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL __R_COMMA result);
|
||||
}
|
||||
|
||||
inline void WilInitialize_CppWinRT()
|
||||
{
|
||||
details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt;
|
||||
if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2)
|
||||
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<std::int32_t>(details::ReportFailure_CaughtException<FailureType::Return>(
|
||||
__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<FailureType::Log>(__R_FN_CALL_FULL __R_COMMA result);
|
||||
}
|
||||
|
||||
inline void WilInitialize_CppWinRT()
|
||||
{
|
||||
details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt;
|
||||
if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2)
|
||||
{
|
||||
WI_ASSERT(winrt_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 <typename T>
|
||||
auto get_abi(T const& object) noexcept
|
||||
{
|
||||
return winrt::get_abi(object);
|
||||
}
|
||||
|
||||
inline auto get_abi(winrt::hstring const& object) noexcept
|
||||
{
|
||||
return static_cast<HSTRING>(winrt::get_abi(object));
|
||||
}
|
||||
|
||||
inline auto str_raw_ptr(const winrt::hstring& str) noexcept
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto put_abi(T& object) noexcept
|
||||
{
|
||||
return winrt::put_abi(object);
|
||||
}
|
||||
|
||||
inline auto put_abi(winrt::hstring& object) noexcept
|
||||
{
|
||||
return reinterpret_cast<HSTRING*>(winrt::put_abi(object));
|
||||
}
|
||||
|
||||
inline ::IUnknown* com_raw_ptr(const winrt::Windows::Foundation::IUnknown& ptr) noexcept
|
||||
{
|
||||
return static_cast<::IUnknown*>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Needed to power wil::cx_object_from_abi that requires IInspectable
|
||||
inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectable& ptr) noexcept
|
||||
{
|
||||
return static_cast<::IInspectable*>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Taken from the docs.microsoft.com article
|
||||
template <typename T>
|
||||
T convert_from_abi(::IUnknown* from)
|
||||
{
|
||||
T to{nullptr}; // `T` is a projected type.
|
||||
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(to)));
|
||||
return to;
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on the factory. Example:
|
||||
// winrt::InputPane inputPane = wil::capture_interop<winrt::InputPane>(&IInputPaneInterop::GetForWindow, hwnd);
|
||||
// If the method produces something different from the factory type:
|
||||
// winrt::IAsyncAction action = wil::capture_interop<winrt::IAsyncAction, winrt::AccountsSettingsPane>(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd);
|
||||
template <typename WinRTResult, typename WinRTFactory = WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
|
||||
auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args)
|
||||
{
|
||||
auto interop = winrt::get_activation_factory<WinRTFactory, Interface>();
|
||||
return winrt::capture<WinRTResult>(interop, method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on an instance. Example:
|
||||
// winrt::UserActivitySession session = wil::capture_interop<winrt::UserActivitySession>(activity, &IUserActivityInterop::CreateSessionForWindow, hwnd);
|
||||
template <typename WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
|
||||
auto capture_interop(winrt::Windows::Foundation::IUnknown const& o, HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args)
|
||||
{
|
||||
return winrt::capture<WinRTResult>(o.as<Interface>(), method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Holds a reference to the host C++/WinRT module to prevent it from being unloaded.
|
||||
Normally, this is done by being in an IAsyncOperation coroutine or by holding a strong
|
||||
reference to a C++/WinRT object hosted in the same module, but if you have neither,
|
||||
you will need to hold a reference explicitly. For the WRL equivalent, see wrl_module_reference.
|
||||
|
||||
This can be used as a base, which permits EBO:
|
||||
@code
|
||||
struct NonWinrtObject : wil::winrt_module_reference
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
@endcode
|
||||
|
||||
Or it can be used as a member (with [[no_unique_address]] to avoid
|
||||
occupying any memory):
|
||||
@code
|
||||
struct NonWinrtObject
|
||||
{
|
||||
int value;
|
||||
|
||||
[[no_unique_address]] wil::winrt_module_reference module_ref;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
@endcode
|
||||
|
||||
If using it to prevent the host DLL from unloading while a thread
|
||||
or threadpool work item is still running, create the object before
|
||||
starting the thread, and pass it to the thread. This avoids a race
|
||||
condition where the host DLL could get unloaded before the thread starts.
|
||||
@code
|
||||
std::thread([module_ref = wil::winrt_module_reference()]() { do_background_work(); });
|
||||
|
||||
// Don't do this (race condition)
|
||||
std::thread([]() { wil::winrt_module_reference module_ref; do_background_work(); }); // WRONG
|
||||
@endcode
|
||||
|
||||
Also useful in coroutines that neither capture DLL-hosted COM objects, nor are themselves
|
||||
DLL-hosted COM objects. (If the coroutine returns IAsyncAction or captures a get_strong()
|
||||
of its containing WinRT class, then the IAsyncAction or strong reference will itself keep
|
||||
a strong reference to the host module.)
|
||||
@code
|
||||
winrt::fire_and_forget ContinueBackgroundWork()
|
||||
{
|
||||
// prevent DLL from unloading while we are running on a background thread.
|
||||
// Do this before switching to the background thread.
|
||||
wil::winrt_module_reference module_ref;
|
||||
|
||||
co_await winrt::resume_background();
|
||||
do_background_work();
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
struct [[nodiscard]] winrt_module_reference
|
||||
{
|
||||
winrt_module_reference()
|
||||
// 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 <typename T> 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<HSTRING>(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<MyThingT<MyThing>,
|
||||
Version2, IMyThing2>
|
||||
{
|
||||
// implementation goes here
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
If `Version2::IsEnabled()` returns `false`, then the `QueryInterface`
|
||||
for `IMyThing2` will fail.
|
||||
|
||||
Any interface not listed as conditional is assumed to be enabled unconditionally.
|
||||
|
||||
You can add additional Version / Interface pairs to the template parameter list.
|
||||
Interfaces may be conditionalized on at most one Version class. If you need a
|
||||
complex conditional, create a new helper class.
|
||||
|
||||
@code
|
||||
// Helper class for testing two Versions.
|
||||
struct Version2_or_greater {
|
||||
static bool IsEnabled() { return Version2::IsEnabled() || Version3::IsEnabled(); }
|
||||
};
|
||||
|
||||
// This implementation supports IMyThing2 if either Version2 or Version3 is enabled,
|
||||
// and supports IMyThing3 only if Version3 is enabled.
|
||||
struct MyThing : wil::winrt_conditionally_implements<MyThingT<MyThing>,
|
||||
Version2_or_greater, IMyThing2, Version3, IMyThing3>
|
||||
{
|
||||
// implementation goes here
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
template <typename Implements, typename... Rest>
|
||||
struct winrt_conditionally_implements : Implements
|
||||
{
|
||||
using Implements::Implements;
|
||||
|
||||
void* find_interface(winrt::guid const& iid) const noexcept override
|
||||
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<Rest...>>(iid))
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
template <typename T> auto put_abi(T &object) noexcept
|
||||
{
|
||||
return winrt::put_abi(object);
|
||||
}
|
||||
|
||||
inline auto put_abi(winrt::hstring &object) noexcept
|
||||
{
|
||||
return reinterpret_cast<HSTRING *>(winrt::put_abi(object));
|
||||
}
|
||||
|
||||
inline ::IUnknown *com_raw_ptr(const winrt::Windows::Foundation::IUnknown &ptr) noexcept
|
||||
{
|
||||
return static_cast<::IUnknown *>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Needed to power wil::cx_object_from_abi that requires IInspectable
|
||||
inline ::IInspectable *com_raw_ptr(const winrt::Windows::Foundation::IInspectable &ptr) noexcept
|
||||
{
|
||||
return static_cast<::IInspectable *>(winrt::get_abi(ptr));
|
||||
}
|
||||
|
||||
// Taken from the docs.microsoft.com article
|
||||
template <typename T> T convert_from_abi(::IUnknown *from)
|
||||
{
|
||||
T to{nullptr}; // `T` is a projected type.
|
||||
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(to)));
|
||||
return to;
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on the factory. Example:
|
||||
// winrt::InputPane inputPane = wil::capture_interop<winrt::InputPane>(&IInputPaneInterop::GetForWindow, hwnd);
|
||||
// If the method produces something different from the factory type:
|
||||
// winrt::IAsyncAction action = wil::capture_interop<winrt::IAsyncAction,
|
||||
// winrt::AccountsSettingsPane>(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd);
|
||||
template <typename WinRTResult, typename WinRTFactory = WinRTResult, typename Interface, typename... InterfaceArgs,
|
||||
typename... Args>
|
||||
auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args &&...args)
|
||||
{
|
||||
auto interop = winrt::get_activation_factory<WinRTFactory, Interface>();
|
||||
return winrt::capture<WinRTResult>(interop, method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on an instance. Example:
|
||||
// winrt::UserActivitySession session = wil::capture_interop<winrt::UserActivitySession>(activity,
|
||||
// &IUserActivityInterop::CreateSessionForWindow, hwnd);
|
||||
template <typename WinRTResult, typename Interface, typename... InterfaceArgs, typename... Args>
|
||||
auto capture_interop(winrt::Windows::Foundation::IUnknown const &o,
|
||||
HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args &&...args)
|
||||
{
|
||||
return winrt::capture<WinRTResult>(o.as<Interface>(), method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Holds a reference to the host C++/WinRT module to prevent it from being unloaded.
|
||||
Normally, this is done by being in an IAsyncOperation coroutine or by holding a strong
|
||||
reference to a C++/WinRT object hosted in the same module, but if you have neither,
|
||||
you will need to hold a reference explicitly. For the WRL equivalent, see wrl_module_reference.
|
||||
|
||||
This can be used as a base, which permits EBO:
|
||||
@code
|
||||
struct NonWinrtObject : wil::winrt_module_reference
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
@endcode
|
||||
|
||||
Or it can be used as a member (with [[no_unique_address]] to avoid
|
||||
occupying any memory):
|
||||
@code
|
||||
struct NonWinrtObject
|
||||
{
|
||||
int value;
|
||||
|
||||
[[no_unique_address]] wil::winrt_module_reference module_ref;
|
||||
};
|
||||
|
||||
// DLL will not be unloaded as long as NonWinrtObject is still alive.
|
||||
auto p = std::make_unique<NonWinrtObject>();
|
||||
@endcode
|
||||
|
||||
If using it to prevent the host DLL from unloading while a thread
|
||||
or threadpool work item is still running, create the object before
|
||||
starting the thread, and pass it to the thread. This avoids a race
|
||||
condition where the host DLL could get unloaded before the thread starts.
|
||||
@code
|
||||
std::thread([module_ref = wil::winrt_module_reference()]() { do_background_work(); });
|
||||
|
||||
// Don't do this (race condition)
|
||||
std::thread([]() { wil::winrt_module_reference module_ref; do_background_work(); }); // WRONG
|
||||
@endcode
|
||||
|
||||
Also useful in coroutines that neither capture DLL-hosted COM objects, nor are themselves
|
||||
DLL-hosted COM objects. (If the coroutine returns IAsyncAction or captures a get_strong()
|
||||
of its containing WinRT class, then the IAsyncAction or strong reference will itself keep
|
||||
a strong reference to the host module.)
|
||||
@code
|
||||
winrt::fire_and_forget ContinueBackgroundWork()
|
||||
{
|
||||
// prevent DLL from unloading while we are running on a background thread.
|
||||
// Do this before switching to the background thread.
|
||||
wil::winrt_module_reference module_ref;
|
||||
|
||||
co_await winrt::resume_background();
|
||||
do_background_work();
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
struct [[nodiscard]] winrt_module_reference
|
||||
{
|
||||
winrt_module_reference()
|
||||
{
|
||||
return Implements::find_interface(iid);
|
||||
++winrt::get_module_lock();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
template <std::size_t index, typename Tuple>
|
||||
static bool is_enabled(winrt::guid const& iid)
|
||||
{
|
||||
if constexpr (index >= std::tuple_size_v<Tuple>)
|
||||
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<index + 1, Tuple>>()) ? std::tuple_element_t<index, Tuple>::IsEnabled()
|
||||
: is_enabled<index + 2, Tuple>(iid);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, std::size_t upto, typename Tuple>
|
||||
static constexpr void check_no_duplicates()
|
||||
{
|
||||
if constexpr (index < upto)
|
||||
~winrt_module_reference()
|
||||
{
|
||||
static_assert(
|
||||
!std::is_same_v<std::tuple_element_t<index, Tuple>, std::tuple_element_t<upto, Tuple>>,
|
||||
"Duplicate interfaces found in winrt_conditionally_implements");
|
||||
check_no_duplicates<index + 2, upto, Tuple>();
|
||||
--winrt::get_module_lock();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/** Implements a C++/WinRT class where some interfaces are conditionally supported.
|
||||
@code
|
||||
// Assume the existence of a class "Version2" which says whether
|
||||
// the IMyThing2 interface should be supported.
|
||||
struct Version2 { static bool IsEnabled(); };
|
||||
|
||||
// Declare implementation class which conditionally supports IMyThing2.
|
||||
struct MyThing : wil::winrt_conditionally_implements<MyThingT<MyThing>,
|
||||
Version2, IMyThing2>
|
||||
{
|
||||
// implementation goes here
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
If `Version2::IsEnabled()` returns `false`, then the `QueryInterface`
|
||||
for `IMyThing2` will fail.
|
||||
|
||||
Any interface not listed as conditional is assumed to be enabled unconditionally.
|
||||
|
||||
You can add additional Version / Interface pairs to the template parameter list.
|
||||
Interfaces may be conditionalized on at most one Version class. If you need a
|
||||
complex conditional, create a new helper class.
|
||||
|
||||
@code
|
||||
// Helper class for testing two Versions.
|
||||
struct Version2_or_greater {
|
||||
static bool IsEnabled() { return Version2::IsEnabled() || Version3::IsEnabled(); }
|
||||
};
|
||||
|
||||
// This implementation supports IMyThing2 if either Version2 or Version3 is enabled,
|
||||
// and supports IMyThing3 only if Version3 is enabled.
|
||||
struct MyThing : wil::winrt_conditionally_implements<MyThingT<MyThing>,
|
||||
Version2_or_greater, IMyThing2, Version3, IMyThing3>
|
||||
{
|
||||
// implementation goes here
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
template <typename Implements, typename... Rest> struct winrt_conditionally_implements : Implements
|
||||
{
|
||||
using Implements::Implements;
|
||||
|
||||
void *find_interface(winrt::guid const &iid) const noexcept override
|
||||
{
|
||||
static_assert(sizeof...(Rest) % 2 == 0, "Extra template parameters should come in groups of two");
|
||||
if (is_enabled<0, std::tuple<Rest...>>(iid))
|
||||
{
|
||||
return Implements::find_interface(iid);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
template <std::size_t index, typename Tuple> static bool is_enabled(winrt::guid const &iid)
|
||||
{
|
||||
if constexpr (index >= std::tuple_size_v<Tuple>)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
check_no_duplicates<1, index + 1, Tuple>();
|
||||
return (iid == winrt::guid_of<std::tuple_element_t<index + 1, Tuple>>())
|
||||
? std::tuple_element_t<index, Tuple>::IsEnabled()
|
||||
: is_enabled<index + 2, Tuple>(iid);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t index, std::size_t upto, typename Tuple> static constexpr void check_no_duplicates()
|
||||
{
|
||||
if constexpr (index < upto)
|
||||
{
|
||||
static_assert(!std::is_same_v<std::tuple_element_t<index, Tuple>, std::tuple_element_t<upto, Tuple>>,
|
||||
"Duplicate interfaces found in winrt_conditionally_implements");
|
||||
check_no_duplicates<index + 2, upto, Tuple>();
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_CPPWINRT_INCLUDED
|
||||
|
||||
@@ -16,312 +16,305 @@ namespace wil
|
||||
#ifndef __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
|
||||
/// @cond
|
||||
#define __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
|
||||
namespace details
|
||||
{
|
||||
template <typename T>
|
||||
struct single_threaded_property_storage
|
||||
namespace details
|
||||
{
|
||||
T m_value{};
|
||||
single_threaded_property_storage() = default;
|
||||
single_threaded_property_storage(const T& value) : m_value(value)
|
||||
template <typename T> struct single_threaded_property_storage
|
||||
{
|
||||
T m_value{};
|
||||
single_threaded_property_storage() = default;
|
||||
single_threaded_property_storage(const T &value) : m_value(value)
|
||||
{
|
||||
}
|
||||
operator T &()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
operator T const &() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
template <typename Q> auto operator=(Q &&q)
|
||||
{
|
||||
m_value = wistd::forward<Q>(q);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
template <typename T>
|
||||
struct single_threaded_property : std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>,
|
||||
wil::details::single_threaded_property_storage<T>, T>
|
||||
{
|
||||
single_threaded_property() = default;
|
||||
template <typename... TArgs>
|
||||
single_threaded_property(TArgs &&...value) : base_type(std::forward<TArgs>(value)...)
|
||||
{
|
||||
}
|
||||
operator T&()
|
||||
|
||||
using base_type = std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>,
|
||||
wil::details::single_threaded_property_storage<T>, T>;
|
||||
|
||||
T operator()() const
|
||||
{
|
||||
return 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<T> instead.
|
||||
template <typename Q> auto &operator=(Q &&q)
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
template <typename Q>
|
||||
auto operator=(Q&& q)
|
||||
{
|
||||
m_value = wistd::forward<Q>(q);
|
||||
static_cast<base_type &>(*this) = std::forward<Q>(q);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
template <typename T>
|
||||
struct single_threaded_property
|
||||
: std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>, wil::details::single_threaded_property_storage<T>, T>
|
||||
{
|
||||
single_threaded_property() = default;
|
||||
template <typename... TArgs>
|
||||
single_threaded_property(TArgs&&... value) : base_type(std::forward<TArgs>(value)...)
|
||||
template <typename T> struct single_threaded_rw_property : single_threaded_property<T>
|
||||
{
|
||||
}
|
||||
using base_type = single_threaded_property<T>;
|
||||
template <typename... TArgs>
|
||||
single_threaded_rw_property(TArgs &&...value) : base_type(std::forward<TArgs>(value)...)
|
||||
{
|
||||
}
|
||||
|
||||
using base_type =
|
||||
std::conditional_t<std::is_scalar_v<T> || std::is_final_v<T>, wil::details::single_threaded_property_storage<T>, T>;
|
||||
using base_type::operator();
|
||||
|
||||
T operator()() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
// needed in lieu of deducing-this
|
||||
template <typename Q> auto &operator()(Q &&q)
|
||||
{
|
||||
return *this = std::forward<Q>(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<T> instead.
|
||||
template <typename Q>
|
||||
auto& operator=(Q&& q)
|
||||
{
|
||||
static_cast<base_type&>(*this) = std::forward<Q>(q);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct single_threaded_rw_property : single_threaded_property<T>
|
||||
{
|
||||
using base_type = single_threaded_property<T>;
|
||||
template <typename... TArgs>
|
||||
single_threaded_rw_property(TArgs&&... value) : base_type(std::forward<TArgs>(value)...)
|
||||
{
|
||||
}
|
||||
|
||||
using base_type::operator();
|
||||
|
||||
// needed in lieu of deducing-this
|
||||
template <typename Q>
|
||||
auto& operator()(Q&& q)
|
||||
{
|
||||
return *this = std::forward<Q>(q);
|
||||
}
|
||||
|
||||
// needed in lieu of deducing-this
|
||||
template <typename Q>
|
||||
auto& operator=(Q&& q)
|
||||
{
|
||||
base_type::operator=(std::forward<Q>(q));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
// needed in lieu of deducing-this
|
||||
template <typename Q> auto &operator=(Q &&q)
|
||||
{
|
||||
base_type::operator=(std::forward<Q>(q));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
|
||||
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)) || \
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)) || \
|
||||
defined(WIL_DOXYGEN) // WinRT / XAML helpers
|
||||
/// @cond
|
||||
#define __WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION
|
||||
namespace details
|
||||
{
|
||||
template <typename T>
|
||||
struct event_base
|
||||
namespace details
|
||||
{
|
||||
winrt::event_token operator()(const T& handler)
|
||||
template <typename T> 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 <typename... TArgs>
|
||||
auto invoke(TArgs&&... args)
|
||||
{
|
||||
return m_handler(std::forward<TArgs>(args)...);
|
||||
}
|
||||
template <typename... TArgs> auto invoke(TArgs &&...args)
|
||||
{
|
||||
return m_handler(std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::event<T> m_handler;
|
||||
private:
|
||||
winrt::event<T> m_handler;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* @brief A default event handler that maps to
|
||||
* [Windows.Foundation.EventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.eventhandler-1).
|
||||
* @tparam T The event data type.
|
||||
*/
|
||||
template <typename T> struct untyped_event : wil::details::event_base<winrt::Windows::Foundation::EventHandler<T>>
|
||||
{
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/**
|
||||
* @brief A default event handler that maps to
|
||||
* [Windows.Foundation.EventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.eventhandler-1).
|
||||
* @tparam T The event data type.
|
||||
*/
|
||||
template <typename T>
|
||||
struct untyped_event : wil::details::event_base<winrt::Windows::Foundation::EventHandler<T>>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A default event handler that maps to
|
||||
* [Windows.Foundation.TypedEventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.typedeventhandler-2).
|
||||
* @tparam T The event data type.
|
||||
* @details Usage example:
|
||||
* @code
|
||||
* // In IDL, this corresponds to:
|
||||
* // event Windows.Foundation.TypedEventHandler<ModalPage, String> OkClicked;
|
||||
* wil::typed_event<MarkupSample::ModalPage, winrt::hstring> OkClicked;
|
||||
* @endcode
|
||||
*/
|
||||
template <typename TSender, typename TArgs>
|
||||
struct typed_event : wil::details::event_base<winrt::Windows::Foundation::TypedEventHandler<TSender, TArgs>>
|
||||
{
|
||||
};
|
||||
/**
|
||||
* @brief A default event handler that maps to
|
||||
* [Windows.Foundation.TypedEventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.typedeventhandler-2).
|
||||
* @tparam T The event data type.
|
||||
* @details Usage example:
|
||||
* @code
|
||||
* // In IDL, this corresponds to:
|
||||
* // event Windows.Foundation.TypedEventHandler<ModalPage, String> OkClicked;
|
||||
* wil::typed_event<MarkupSample::ModalPage, winrt::hstring> OkClicked;
|
||||
* @endcode
|
||||
*/
|
||||
template <typename TSender, typename TArgs>
|
||||
struct typed_event : wil::details::event_base<winrt::Windows::Foundation::TypedEventHandler<TSender, TArgs>>
|
||||
{
|
||||
};
|
||||
|
||||
#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)
|
||||
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || defined(WINRT_Windows_UI_Xaml_Data_H))) || \
|
||||
#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<MyPage>, wil::notify_property_changed_base<MyPage>
|
||||
* {
|
||||
* wil::single_threaded_notifying_property<int> MyInt;
|
||||
* MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { }
|
||||
* // or
|
||||
* WIL_NOTIFYING_PROPERTY(int, MyInt, 42);
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T, typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler, typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
|
||||
struct notify_property_changed_base
|
||||
{
|
||||
using Type = T;
|
||||
auto PropertyChanged(Xaml_Data_PropertyChangedEventHandler const& value)
|
||||
{
|
||||
return m_propertyChanged.add(value);
|
||||
}
|
||||
|
||||
void PropertyChanged(winrt::event_token const& token)
|
||||
{
|
||||
m_propertyChanged.remove(token);
|
||||
}
|
||||
|
||||
Type& self()
|
||||
{
|
||||
return *static_cast<Type*>(this);
|
||||
}
|
||||
} // 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<MyPage>, wil::notify_property_changed_base<MyPage>
|
||||
* {
|
||||
* // modify MyInt
|
||||
* // MyInt = ...
|
||||
*
|
||||
* // now send a notification to update the bound UI elements
|
||||
* RaisePropertyChanged(L"MyInt");
|
||||
* }
|
||||
* wil::single_threaded_notifying_property<int> MyInt;
|
||||
* MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { }
|
||||
* // or
|
||||
* WIL_NOTIFYING_PROPERTY(int, MyInt, 42);
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
auto RaisePropertyChanged(std::wstring_view name)
|
||||
template <typename T,
|
||||
typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler,
|
||||
typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
|
||||
struct notify_property_changed_base
|
||||
{
|
||||
return m_propertyChanged(self(), Xaml_Data_PropertyChangedEventArgs{name});
|
||||
}
|
||||
|
||||
protected:
|
||||
winrt::event<Xaml_Data_PropertyChangedEventHandler> m_propertyChanged;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements a property type with notifications
|
||||
* @tparam T the property type
|
||||
* @details Use the INIT_NOTIFY_PROPERTY macro to initialize this property in your class constructor. This will set up the
|
||||
* right property name, and bind it to the `notify_property_changed_base` implementation.
|
||||
*/
|
||||
template <typename T, typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler, typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
|
||||
struct single_threaded_notifying_property : single_threaded_rw_property<T>
|
||||
{
|
||||
using Type = T;
|
||||
using base_type = single_threaded_rw_property<T>;
|
||||
using base_type::operator();
|
||||
|
||||
template <typename Q>
|
||||
auto& operator()(Q&& q)
|
||||
{
|
||||
return *this = std::forward<Q>(q);
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
auto& operator=(Q&& q)
|
||||
{
|
||||
if (q != this->operator()())
|
||||
using Type = T;
|
||||
auto PropertyChanged(Xaml_Data_PropertyChangedEventHandler const &value)
|
||||
{
|
||||
static_cast<base_type&>(*this) = std::forward<Q>(q);
|
||||
if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr))
|
||||
{
|
||||
(*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{m_name});
|
||||
}
|
||||
return m_propertyChanged.add(value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
single_threaded_notifying_property(
|
||||
winrt::event<Xaml_Data_PropertyChangedEventHandler>* npc,
|
||||
const winrt::Windows::Foundation::IInspectable& sender,
|
||||
std::wstring_view name,
|
||||
TArgs&&... args) :
|
||||
single_threaded_rw_property<T>(std::forward<TArgs...>(args)...), m_name(name), m_npc(npc), m_sender(sender)
|
||||
void PropertyChanged(winrt::event_token const &token)
|
||||
{
|
||||
m_propertyChanged.remove(token);
|
||||
}
|
||||
|
||||
Type &self()
|
||||
{
|
||||
return *static_cast<Type *>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Raises a property change notification event
|
||||
* @param name The name of the property
|
||||
* @return
|
||||
* @details Usage example\n
|
||||
* C++
|
||||
* @code
|
||||
* void MyPage::DoSomething()
|
||||
* {
|
||||
* // modify MyInt
|
||||
* // MyInt = ...
|
||||
*
|
||||
* // now send a notification to update the bound UI elements
|
||||
* RaisePropertyChanged(L"MyInt");
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
auto RaisePropertyChanged(std::wstring_view name)
|
||||
{
|
||||
return m_propertyChanged(self(), Xaml_Data_PropertyChangedEventArgs{name});
|
||||
}
|
||||
|
||||
protected:
|
||||
winrt::event<Xaml_Data_PropertyChangedEventHandler> m_propertyChanged;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements a property type with notifications
|
||||
* @tparam T the property type
|
||||
* @details Use the INIT_NOTIFY_PROPERTY macro to initialize this property in your class constructor. This will set
|
||||
* up the right property name, and bind it to the `notify_property_changed_base` implementation.
|
||||
*/
|
||||
template <typename T,
|
||||
typename Xaml_Data_PropertyChangedEventHandler = wil::details::Xaml_Data_PropertyChangedEventHandler,
|
||||
typename Xaml_Data_PropertyChangedEventArgs = wil::details::Xaml_Data_PropertyChangedEventArgs>
|
||||
struct single_threaded_notifying_property : single_threaded_rw_property<T>
|
||||
{
|
||||
}
|
||||
using Type = T;
|
||||
using base_type = single_threaded_rw_property<T>;
|
||||
using base_type::operator();
|
||||
|
||||
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 <typename Q> auto &operator()(Q &&q)
|
||||
{
|
||||
return *this = std::forward<Q>(q);
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring_view m_name;
|
||||
winrt::event<Xaml_Data_PropertyChangedEventHandler>* m_npc;
|
||||
winrt::weak_ref<winrt::Windows::Foundation::IInspectable> m_sender;
|
||||
};
|
||||
template <typename Q> auto &operator=(Q &&q)
|
||||
{
|
||||
if (q != this->operator()())
|
||||
{
|
||||
static_cast<base_type &>(*this) = std::forward<Q>(q);
|
||||
if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr))
|
||||
{
|
||||
(*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{m_name});
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
single_threaded_notifying_property(winrt::event<Xaml_Data_PropertyChangedEventHandler> *npc,
|
||||
const winrt::Windows::Foundation::IInspectable &sender,
|
||||
std::wstring_view name, TArgs &&...args)
|
||||
: single_threaded_rw_property<T>(std::forward<TArgs...>(args)...), m_name(name), m_npc(npc),
|
||||
m_sender(sender)
|
||||
{
|
||||
}
|
||||
|
||||
single_threaded_notifying_property(const single_threaded_notifying_property &) = default;
|
||||
single_threaded_notifying_property(single_threaded_notifying_property &&) = default;
|
||||
std::wstring_view Name() const noexcept
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring_view m_name;
|
||||
winrt::event<Xaml_Data_PropertyChangedEventHandler> *m_npc;
|
||||
winrt::weak_ref<winrt::Windows::Foundation::IInspectable> m_sender;
|
||||
};
|
||||
|
||||
/**
|
||||
* @def WIL_NOTIFYING_PROPERTY
|
||||
* @brief use this to stamp out a property that calls RaisePropertyChanged upon changing its value. This is a zero-storage
|
||||
* alternative to wil::single_threaded_notifying_property<T>.
|
||||
* @brief use this to stamp out a property that calls RaisePropertyChanged upon changing its value. This is a
|
||||
* zero-storage alternative to wil::single_threaded_notifying_property<T>.
|
||||
* @details You can pass an initializer list for the initial property value in the variadic arguments to this macro.
|
||||
*/
|
||||
#define WIL_NOTIFYING_PROPERTY(type, name, ...) \
|
||||
type m_##name{__VA_ARGS__}; \
|
||||
auto name() const noexcept \
|
||||
{ \
|
||||
return m_##name; \
|
||||
} \
|
||||
auto& name(type value) \
|
||||
{ \
|
||||
if (m_##name != value) \
|
||||
{ \
|
||||
m_##name = std::move(value); \
|
||||
RaisePropertyChanged(L"" #name); \
|
||||
} \
|
||||
return *this; \
|
||||
#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
|
||||
|
||||
@@ -17,152 +17,151 @@
|
||||
/// @cond
|
||||
namespace wil::details
|
||||
{
|
||||
struct dispatcher_RunAsync
|
||||
{
|
||||
template <typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
|
||||
struct dispatcher_RunAsync
|
||||
{
|
||||
dispatcher.RunAsync(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
template <typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const &dispatcher, Args &&...args)
|
||||
{
|
||||
dispatcher.RunAsync(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
struct dispatcher_TryEnqueue
|
||||
{
|
||||
template <typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const& dispatcher, Args&&... args)
|
||||
struct dispatcher_TryEnqueue
|
||||
{
|
||||
dispatcher.TryEnqueue(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
template <typename Dispatcher, typename... Args>
|
||||
static void Schedule(Dispatcher const &dispatcher, Args &&...args)
|
||||
{
|
||||
dispatcher.TryEnqueue(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Dispatcher>
|
||||
struct dispatcher_traits;
|
||||
template <typename Dispatcher> struct dispatcher_traits;
|
||||
} // namespace wil::details
|
||||
|
||||
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
|
||||
#include <experimental/coroutine>
|
||||
namespace wil::details
|
||||
{
|
||||
template <typename T = void>
|
||||
using coroutine_handle = std::experimental::coroutine_handle<T>;
|
||||
template <typename T = void> using coroutine_handle = std::experimental::coroutine_handle<T>;
|
||||
}
|
||||
#elif defined(__cpp_impl_coroutine)
|
||||
#include <coroutine>
|
||||
#if (__cpp_lib_coroutine >= 201902L)
|
||||
namespace wil::details
|
||||
{
|
||||
template <typename T = void>
|
||||
using coroutine_handle = std::coroutine_handle<T>;
|
||||
template <typename T = void> using coroutine_handle = std::coroutine_handle<T>;
|
||||
}
|
||||
#endif // __cpp_lib_coroutine
|
||||
#endif // __cpp_impl_coroutine
|
||||
/// @endcond
|
||||
|
||||
#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || \
|
||||
#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 <winrt/Namespace.h> header before including
|
||||
//! wil/cppwinrt_helpers.h. It is okay to include wil/cppwinrt_helpers.h multiple times:
|
||||
//! support will be enabled for any winrt/Namespace.h headers that were included since
|
||||
//! the previous inclusion of wil/cppwinrt_headers.h.
|
||||
template <typename Dispatcher>
|
||||
[[nodiscard]] auto resume_foreground(
|
||||
Dispatcher const& dispatcher,
|
||||
typename details::dispatcher_traits<Dispatcher>::Priority priority = details::dispatcher_traits<Dispatcher>::Priority::Normal)
|
||||
{
|
||||
using Traits = details::dispatcher_traits<Dispatcher>;
|
||||
using Priority = typename Traits::Priority;
|
||||
using Handler = typename Traits::Handler;
|
||||
|
||||
struct awaitable
|
||||
//! Resumes coroutine execution on the thread associated with the dispatcher, or throws
|
||||
//! an exception (from an arbitrary thread) if unable. Supported dispatchers are
|
||||
//! Windows.System.DispatcherQueue, Microsoft.System.DispatcherQueue,
|
||||
//! Microsoft.UI.Dispatching.DispatcherQueue, and Windows.UI.Core.CoreDispatcher,
|
||||
//! but you must include the corresponding <winrt/Namespace.h> header before including
|
||||
//! wil/cppwinrt_helpers.h. It is okay to include wil/cppwinrt_helpers.h multiple times:
|
||||
//! support will be enabled for any winrt/Namespace.h headers that were included since
|
||||
//! the previous inclusion of wil/cppwinrt_headers.h.
|
||||
template <typename Dispatcher>
|
||||
[[nodiscard]] auto resume_foreground(Dispatcher const &dispatcher,
|
||||
typename details::dispatcher_traits<Dispatcher>::Priority priority =
|
||||
details::dispatcher_traits<Dispatcher>::Priority::Normal)
|
||||
{
|
||||
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<Dispatcher>;
|
||||
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<winrt::hresult>(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<winrt::hresult>(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE)
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Dispatcher const &m_dispatcher;
|
||||
Priority const m_priority;
|
||||
details::dispatched_handler_state m_state;
|
||||
};
|
||||
return awaitable{dispatcher, priority};
|
||||
}
|
||||
} // namespace wil
|
||||
#endif // Coroutines are supported
|
||||
|
||||
@@ -173,13 +172,12 @@ template <typename Dispatcher>
|
||||
#define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template <>
|
||||
struct dispatcher_traits<winrt::Windows::UI::Core::CoreDispatcher>
|
||||
{
|
||||
using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority;
|
||||
using Handler = winrt::Windows::UI::Core::DispatchedHandler;
|
||||
using Scheduler = dispatcher_RunAsync;
|
||||
};
|
||||
template <> struct dispatcher_traits<winrt::Windows::UI::Core::CoreDispatcher>
|
||||
{
|
||||
using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority;
|
||||
using Handler = winrt::Windows::UI::Core::DispatchedHandler;
|
||||
using Scheduler = dispatcher_RunAsync;
|
||||
};
|
||||
} // namespace wil::details
|
||||
#endif // __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS
|
||||
|
||||
@@ -187,13 +185,12 @@ struct dispatcher_traits<winrt::Windows::UI::Core::CoreDispatcher>
|
||||
#define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template <>
|
||||
struct dispatcher_traits<winrt::Windows::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Windows::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Windows::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
template <> struct dispatcher_traits<winrt::Windows::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Windows::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Windows::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
} // namespace wil::details
|
||||
#endif // __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS
|
||||
|
||||
@@ -201,13 +198,12 @@ struct dispatcher_traits<winrt::Windows::System::DispatcherQueue>
|
||||
#define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template <>
|
||||
struct dispatcher_traits<winrt::Microsoft::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
template <> struct dispatcher_traits<winrt::Microsoft::System::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::System::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::System::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
} // namespace wil::details
|
||||
#endif // __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS
|
||||
|
||||
@@ -215,144 +211,140 @@ struct dispatcher_traits<winrt::Microsoft::System::DispatcherQueue>
|
||||
#define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
|
||||
namespace wil::details
|
||||
{
|
||||
template <>
|
||||
struct dispatcher_traits<winrt::Microsoft::UI::Dispatching::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
template <> struct dispatcher_traits<winrt::Microsoft::UI::Dispatching::DispatcherQueue>
|
||||
{
|
||||
using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority;
|
||||
using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler;
|
||||
using Scheduler = dispatcher_TryEnqueue;
|
||||
};
|
||||
} // namespace wil::details
|
||||
#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS
|
||||
/// @endcond
|
||||
|
||||
#if (defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)) || \
|
||||
#if (defined(WINRT_Windows_Foundation_Collections_H) && \
|
||||
!defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS)) || \
|
||||
defined(WIL_DOXYGEN)
|
||||
/// @cond
|
||||
#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS
|
||||
/// @endcond
|
||||
namespace wil
|
||||
{
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <typename T>
|
||||
struct is_winrt_vector_like
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename U,
|
||||
typename = decltype(std::declval<U>().GetMany(std::declval<U>().Size(), winrt::array_view<decltype(std::declval<U>().GetAt(0))>{}))>
|
||||
static constexpr bool get_value(int)
|
||||
template <typename T> struct is_winrt_vector_like
|
||||
{
|
||||
return true;
|
||||
}
|
||||
template <typename>
|
||||
static constexpr bool get_value(...)
|
||||
private:
|
||||
template <typename U,
|
||||
typename = decltype(std::declval<U>().GetMany(
|
||||
std::declval<U>().Size(), winrt::array_view<decltype(std::declval<U>().GetAt(0))>{}))>
|
||||
static constexpr bool get_value(int)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
template <typename> static constexpr bool get_value(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template <typename T> struct is_winrt_iterator_like
|
||||
{
|
||||
return false;
|
||||
private:
|
||||
template <typename U, typename = decltype(std::declval<U>().GetMany(
|
||||
winrt::array_view<decltype(std::declval<U>().Current())>{}))>
|
||||
static constexpr bool get_value(int)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
template <typename> static constexpr bool get_value(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template <typename T> constexpr T empty() noexcept
|
||||
{
|
||||
if constexpr (std::is_base_of_v<winrt::Windows::Foundation::IUnknown, T>)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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<winrt::hstring> collection = GetCollection();
|
||||
std::vector<winrt::hstring> allData = wil::to_vector(collection); // read all data from collection
|
||||
for (winrt::hstring const& item : allData)
|
||||
{
|
||||
private:
|
||||
template <typename U, typename = decltype(std::declval<U>().GetMany(winrt::array_view<decltype(std::declval<U>().Current())>{}))>
|
||||
static constexpr bool get_value(int)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
template <typename>
|
||||
static constexpr bool get_value(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr bool value = get_value<T>(0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr T empty() noexcept
|
||||
// use item
|
||||
}
|
||||
@endcode
|
||||
Can be used for IVector<T>, IVectorView<T>, IIterable<T>, IIterator<T>, and any type or
|
||||
interface that C++/WinRT projects those interfaces for (PropertySet, IMap<T,K>, etc.)
|
||||
Iterable-only types fetch content in units of 64. When used with an iterator, the returned
|
||||
vector contains the iterator's current position and any others after it.
|
||||
*/
|
||||
template <typename TSrc> auto to_vector(TSrc const &src)
|
||||
{
|
||||
if constexpr (std::is_base_of_v<winrt::Windows::Foundation::IUnknown, T>)
|
||||
if constexpr (details::is_winrt_vector_like<TSrc>::value)
|
||||
{
|
||||
return nullptr;
|
||||
using T = decltype(src.GetAt(0));
|
||||
std::vector<T> result;
|
||||
if (auto expected = src.Size())
|
||||
{
|
||||
result.resize(expected + 1, details::empty<T>());
|
||||
auto actual = src.GetMany(0, result);
|
||||
if (actual > expected)
|
||||
{
|
||||
throw winrt::hresult_changed_state();
|
||||
}
|
||||
result.resize(actual, details::empty<T>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if constexpr (details::is_winrt_iterator_like<TSrc>::value)
|
||||
{
|
||||
using T = decltype(src.Current());
|
||||
std::vector<T> result;
|
||||
constexpr uint32_t chunkSize = 64;
|
||||
while (true)
|
||||
{
|
||||
auto const lastSize = result.size();
|
||||
result.resize(lastSize + chunkSize, details::empty<T>());
|
||||
auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize});
|
||||
if (fetched < chunkSize)
|
||||
{
|
||||
result.resize(lastSize + fetched, details::empty<T>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
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<winrt::hstring> collection = GetCollection();
|
||||
std::vector<winrt::hstring> allData = wil::to_vector(collection); // read all data from collection
|
||||
for (winrt::hstring const& item : allData)
|
||||
{
|
||||
// use item
|
||||
}
|
||||
@endcode
|
||||
Can be used for IVector<T>, IVectorView<T>, IIterable<T>, IIterator<T>, and any type or
|
||||
interface that C++/WinRT projects those interfaces for (PropertySet, IMap<T,K>, etc.)
|
||||
Iterable-only types fetch content in units of 64. When used with an iterator, the returned
|
||||
vector contains the iterator's current position and any others after it.
|
||||
*/
|
||||
template <typename TSrc>
|
||||
auto to_vector(TSrc const& src)
|
||||
{
|
||||
if constexpr (details::is_winrt_vector_like<TSrc>::value)
|
||||
{
|
||||
using T = decltype(src.GetAt(0));
|
||||
std::vector<T> result;
|
||||
if (auto expected = src.Size())
|
||||
{
|
||||
result.resize(expected + 1, details::empty<T>());
|
||||
auto actual = src.GetMany(0, result);
|
||||
if (actual > expected)
|
||||
{
|
||||
throw winrt::hresult_changed_state();
|
||||
}
|
||||
result.resize(actual, details::empty<T>());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if constexpr (details::is_winrt_iterator_like<TSrc>::value)
|
||||
{
|
||||
using T = decltype(src.Current());
|
||||
std::vector<T> result;
|
||||
constexpr uint32_t chunkSize = 64;
|
||||
while (true)
|
||||
{
|
||||
auto const lastSize = result.size();
|
||||
result.resize(lastSize + chunkSize, details::empty<T>());
|
||||
auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize});
|
||||
if (fetched < chunkSize)
|
||||
{
|
||||
result.resize(lastSize + fetched, details::empty<T>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return to_vector(src.First());
|
||||
}
|
||||
}
|
||||
} // namespace wil
|
||||
#endif
|
||||
|
||||
#if (defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS)) || \
|
||||
#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 <winrt/Windows.UI.h>
|
||||
//! <Windows.UI.Interop.h> before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION
|
||||
//! is at least NTDDI_WIN10_CU. It is okay to include wil/cppwinrt_helpers.h multiple times:
|
||||
//! support will be enabled for any headers that were included since the previous inclusion
|
||||
//! of wil/cppwinrt_headers.h.
|
||||
inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd)
|
||||
{
|
||||
ABI::Windows::UI::WindowId abiWindowId;
|
||||
winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId));
|
||||
return winrt::Windows::UI::WindowId{abiWindowId.Value};
|
||||
}
|
||||
//! The following methods require that you include both <winrt/Windows.UI.h>
|
||||
//! <Windows.UI.Interop.h> before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION
|
||||
//! is at least NTDDI_WIN10_CU. It is okay to include wil/cppwinrt_helpers.h multiple times:
|
||||
//! support will be enabled for any headers that were included since the previous inclusion
|
||||
//! of wil/cppwinrt_headers.h.
|
||||
inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd)
|
||||
{
|
||||
ABI::Windows::UI::WindowId abiWindowId;
|
||||
winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId));
|
||||
return winrt::Windows::UI::WindowId{abiWindowId.Value};
|
||||
}
|
||||
|
||||
inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId)
|
||||
{
|
||||
HWND hwnd;
|
||||
winrt::check_hresult(::GetWindowFromWindowId({windowId.Value}, &hwnd));
|
||||
return hwnd;
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
@@ -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 <typename Func> void set_notifier(Func &&func)
|
||||
{
|
||||
notifier = std::forward<Func>(func);
|
||||
}
|
||||
|
||||
operator uint32_t() const noexcept
|
||||
void set_notifier(std::nullptr_t) noexcept
|
||||
{
|
||||
notifier = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int32_t> m_count{0};
|
||||
std::function<void()> notifier{};
|
||||
};
|
||||
|
||||
struct notifiable_module_lock final : notifiable_module_lock_base
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void set_notifier(Func&& func)
|
||||
{
|
||||
notifier = std::forward<Func>(func);
|
||||
}
|
||||
|
||||
void set_notifier(std::nullptr_t) noexcept
|
||||
{
|
||||
notifier = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int32_t> m_count{0};
|
||||
std::function<void()> notifier{};
|
||||
};
|
||||
|
||||
struct notifiable_module_lock final : notifiable_module_lock_base
|
||||
{
|
||||
static notifiable_module_lock& instance() noexcept
|
||||
{
|
||||
static notifiable_module_lock lock;
|
||||
return lock;
|
||||
}
|
||||
};
|
||||
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
|
||||
|
||||
@@ -14,63 +14,62 @@
|
||||
#ifndef __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED
|
||||
#define __WIL_CPPWINRT_REGISTER_COM_SERVER_INCLUDED
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <wil/resource.h>
|
||||
#include <wil/cppwinrt.h>
|
||||
#include <vector>
|
||||
#include <wil/cppwinrt.h>
|
||||
#include <wil/resource.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
namespace wil::details
|
||||
{
|
||||
template <typename T>
|
||||
struct CppWinRTClassFactory : winrt::implements<CppWinRTClassFactory<T>, IClassFactory, winrt::no_module_lock>
|
||||
{
|
||||
HRESULT __stdcall CreateInstance(IUnknown* outer, GUID const& iid, void** result) noexcept final
|
||||
try
|
||||
template <typename T>
|
||||
struct CppWinRTClassFactory : winrt::implements<CppWinRTClassFactory<T>, 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<T>().as(iid, result);
|
||||
}
|
||||
return winrt::make_self<T>().as(iid, result);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
CATCH_RETURN()
|
||||
|
||||
HRESULT __stdcall LockServer(BOOL) noexcept final
|
||||
HRESULT __stdcall LockServer(BOOL) noexcept final
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T = void, typename... Rest>
|
||||
void register_com_server(std::vector<wil::unique_com_class_object_cookie> ®istrations)
|
||||
{
|
||||
return S_OK;
|
||||
DWORD registration{};
|
||||
winrt::check_hresult(CoRegisterClassObject(winrt::guid_of<T>(), winrt::make<CppWinRTClassFactory<T>>().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<Rest...>(registrations);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T = void, typename... Rest>
|
||||
void register_com_server(std::vector<wil::unique_com_class_object_cookie>& registrations)
|
||||
{
|
||||
DWORD registration{};
|
||||
winrt::check_hresult(CoRegisterClassObject(
|
||||
winrt::guid_of<T>(), winrt::make<CppWinRTClassFactory<T>>().get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®istration));
|
||||
// This emplace_back is no-throw as wil::register_com_server already reserves enough capacity
|
||||
registrations.emplace_back(registration);
|
||||
register_com_server<Rest...>(registrations);
|
||||
}
|
||||
|
||||
template <>
|
||||
void register_com_server<void>(std::vector<unique_com_class_object_cookie>&)
|
||||
{
|
||||
}
|
||||
template <> void register_com_server<void>(std::vector<unique_com_class_object_cookie> &)
|
||||
{
|
||||
}
|
||||
} // namespace wil::details
|
||||
|
||||
namespace wil
|
||||
{
|
||||
template <typename T, typename... Rest>
|
||||
[[nodiscard]] std::vector<wil::unique_com_class_object_cookie> register_com_server()
|
||||
{
|
||||
std::vector<wil::unique_com_class_object_cookie> registrations;
|
||||
registrations.reserve(sizeof...(Rest) + 1);
|
||||
details::register_com_server<T, Rest...>(registrations);
|
||||
// C++17 doesn't provide guaranteed copy elision, but the copy should be elided nonetheless.
|
||||
return registrations;
|
||||
}
|
||||
template <typename T, typename... Rest>
|
||||
[[nodiscard]] std::vector<wil::unique_com_class_object_cookie> register_com_server()
|
||||
{
|
||||
std::vector<wil::unique_com_class_object_cookie> registrations;
|
||||
registrations.reserve(sizeof...(Rest) + 1);
|
||||
details::register_com_server<T, Rest...>(registrations);
|
||||
// C++17 doesn't provide guaranteed copy elision, but the copy should be elided nonetheless.
|
||||
return registrations;
|
||||
}
|
||||
} // namespace wil
|
||||
|
||||
#endif
|
||||
@@ -32,49 +32,48 @@
|
||||
//
|
||||
namespace wil
|
||||
{
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <typename TCppWinRTClass>
|
||||
class module_count_wrapper : public TCppWinRTClass
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
public:
|
||||
module_count_wrapper()
|
||||
template <typename TCppWinRTClass> 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 <typename TCppWinRTClass> class wrl_factory_for_winrt_com_class : public ::Microsoft::WRL::ClassFactory<>
|
||||
{
|
||||
public:
|
||||
IFACEMETHODIMP CreateInstance(_In_opt_ ::IUnknown *unknownOuter, REFIID riid,
|
||||
_COM_Outptr_ void **object) noexcept
|
||||
try
|
||||
{
|
||||
*object = nullptr;
|
||||
RETURN_HR_IF(CLASS_E_NOAGGREGATION, unknownOuter != nullptr);
|
||||
|
||||
return winrt::make<details::module_count_wrapper<TCppWinRTClass>>().as(riid, object);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
template <typename TCppWinRTClass>
|
||||
class wrl_factory_for_winrt_com_class : public ::Microsoft::WRL::ClassFactory<>
|
||||
{
|
||||
public:
|
||||
IFACEMETHODIMP CreateInstance(_In_opt_ ::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept
|
||||
try
|
||||
{
|
||||
*object = nullptr;
|
||||
RETURN_HR_IF(CLASS_E_NOAGGREGATION, unknownOuter != nullptr);
|
||||
|
||||
return winrt::make<details::module_count_wrapper<TCppWinRTClass>>().as(riid, object);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
};
|
||||
} // namespace wil
|
||||
|
||||
#define CoCreatableCppWinRtClass(className) \
|
||||
#define CoCreatableCppWinRtClass(className) \
|
||||
CoCreatableClassWithFactory(className, ::wil::wrl_factory_for_winrt_com_class<className>)
|
||||
|
||||
#endif // __WIL_CPPWINRT_WRL_INCLUDED
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(
|
||||
__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
|
||||
template <FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(
|
||||
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList);
|
||||
|
||||
namespace __R_NS_NAME
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(
|
||||
__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
|
||||
template <FailureType>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL,
|
||||
_Printf_format_string_ PCSTR formatString,
|
||||
va_list argList);
|
||||
|
||||
namespace __R_NS_NAME
|
||||
{
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
||||
{
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
|
||||
}
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
||||
{
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
|
||||
}
|
||||
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtExceptionMsg)
|
||||
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, formatString);
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtExceptionMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
|
||||
}
|
||||
__R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtExceptionMsg)
|
||||
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, formatString);
|
||||
__R_FN_LOCALS;
|
||||
return wil::details::ReportStatus_CaughtExceptionMsg<FailureType::Return>(
|
||||
__R_DIRECT_FN_CALL formatString, argList);
|
||||
}
|
||||
#endif
|
||||
} // namespace __R_NS_NAME
|
||||
} // namespace __R_NS_NAME
|
||||
|
||||
template <FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status;
|
||||
}
|
||||
template <FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL,
|
||||
SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported)
|
||||
.status;
|
||||
}
|
||||
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::FailFast>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(
|
||||
ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
|
||||
}
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::FailFast>(
|
||||
__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported)
|
||||
.status);
|
||||
}
|
||||
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::Exception>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(
|
||||
ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status);
|
||||
}
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtException<FailureType::Exception>(
|
||||
__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
||||
{
|
||||
wchar_t message[2048];
|
||||
message[0] = L'\0';
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported)
|
||||
.status);
|
||||
}
|
||||
|
||||
template <FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status;
|
||||
}
|
||||
template <FailureType T>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL,
|
||||
_Printf_format_string_ PCSTR formatString,
|
||||
va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message),
|
||||
SupportedExceptions::Default)
|
||||
.status;
|
||||
}
|
||||
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::FailFast>(
|
||||
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
||||
.status);
|
||||
}
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::FailFast>(
|
||||
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
||||
.status);
|
||||
}
|
||||
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::Exception>(
|
||||
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
||||
.status);
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
template <>
|
||||
__declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg<FailureType::Exception>(
|
||||
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
||||
{
|
||||
// Pre-populate the buffer with our message, the exception message will be added to it...
|
||||
wchar_t message[2048];
|
||||
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
||||
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
||||
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
|
||||
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
||||
.status);
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_NT_RESULTMACROS_INCLUDED
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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 <OleAuto.h> // RestrictedErrorInfo uses BSTRs :(
|
||||
#include <winstring.h>
|
||||
#include "resource.h"
|
||||
#include "com.h"
|
||||
#include <roerrorapi.h>
|
||||
#include <winstring.h>
|
||||
|
||||
namespace wil
|
||||
{
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame.
|
||||
inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT
|
||||
/// @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<IRestrictedErrorInfo> restrictedErrorInformation;
|
||||
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
|
||||
{
|
||||
// This thread already has an error origination payload. Don't originate again if it has the same
|
||||
// HRESULT that we are observing right now.
|
||||
wil::unique_bstr descriptionUnused;
|
||||
HRESULT existingHr = failure.hr;
|
||||
wil::unique_bstr restrictedDescriptionUnused;
|
||||
wil::unique_bstr capabilitySidUnused;
|
||||
if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(
|
||||
&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)))
|
||||
{
|
||||
shouldOriginate = (failure.hr != existingHr);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldOriginate)
|
||||
{
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
wil::unique_hmodule errorModule;
|
||||
if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule))
|
||||
{
|
||||
auto pfn = details::GetProcAddress<decltype(&::RoOriginateErrorW)>(errorModule.get(),
|
||||
"RoOriginateErrorW");
|
||||
if (pfn != nullptr)
|
||||
{
|
||||
pfn(failure.hr, 0, failure.pszMessage);
|
||||
}
|
||||
}
|
||||
#else // DESKTOP | SYSTEM
|
||||
::RoOriginateErrorW(failure.hr, 0, failure.pszMessage);
|
||||
#endif // DESKTOP | SYSTEM
|
||||
}
|
||||
else if (restrictedErrorInformation)
|
||||
{
|
||||
// GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and
|
||||
// an error was already present, then we need to restore the error information for later
|
||||
// observation.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method will check for the presence of stowed exception data on the current thread. If such data exists,
|
||||
// and the HRESULT matches the current failure, then we will call RoFailFastWithErrorContext.
|
||||
// RoFailFastWithErrorContext in this situation will result in -VASTLY- improved crash bucketing. It is hard to
|
||||
// express just how much better. In other cases we just return and the calling method fails fast the same way
|
||||
// it always has.
|
||||
inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const &failure) WI_NOEXCEPT
|
||||
{
|
||||
wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
|
||||
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
|
||||
{
|
||||
// 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<decltype(&::RoOriginateErrorW)>(errorModule.get(), "RoOriginateErrorW");
|
||||
if (pfn != nullptr)
|
||||
{
|
||||
pfn(failure.hr, 0, failure.pszMessage);
|
||||
}
|
||||
}
|
||||
#else // DESKTOP | SYSTEM
|
||||
::RoOriginateErrorW(failure.hr, 0, failure.pszMessage);
|
||||
#endif // DESKTOP | SYSTEM
|
||||
}
|
||||
else if (restrictedErrorInformation)
|
||||
{
|
||||
// GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was
|
||||
// already present, then we need to restore the error information for later observation.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method will check for the presence of stowed exception data on the current thread. If such data exists, and the
|
||||
// HRESULT matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this
|
||||
// situation will result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we
|
||||
// just return and the calling method fails fast the same way it always has.
|
||||
inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT
|
||||
{
|
||||
wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
|
||||
if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
|
||||
{
|
||||
wil::unique_bstr descriptionUnused;
|
||||
HRESULT existingHr = failure.hr;
|
||||
wil::unique_bstr restrictedDescriptionUnused;
|
||||
wil::unique_bstr capabilitySidUnused;
|
||||
if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(
|
||||
&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) &&
|
||||
(existingHr == failure.hr))
|
||||
{
|
||||
// GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for
|
||||
// RoFailFastWithErrorContext so we must restore it via SetRestrictedErrorInfo first.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
RoFailFastWithErrorContext(existingHr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing
|
||||
// fast in this method, so it is available in the debugger just-in-case.
|
||||
SetRestrictedErrorInfo(restrictedErrorInformation.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
} // namespace wil
|
||||
|
||||
// Automatically call RoOriginateError upon error origination by including this file
|
||||
|
||||
@@ -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 <typename TReturnType>
|
||||
struct call_adapter
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <typename... TArgs>
|
||||
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 <typename TReturnType> struct call_adapter
|
||||
{
|
||||
return wistd::invoke(wistd::forward<TArgs>(args)...);
|
||||
}
|
||||
};
|
||||
template <typename... TArgs> static HRESULT call(TArgs &&...args)
|
||||
{
|
||||
return wistd::invoke(wistd::forward<TArgs>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_adapter<void>
|
||||
{
|
||||
template <typename... TArgs>
|
||||
static HRESULT call(TArgs&&... args)
|
||||
template <> struct call_adapter<void>
|
||||
{
|
||||
wistd::invoke(wistd::forward<TArgs>(args)...);
|
||||
template <typename... TArgs> static HRESULT call(TArgs &&...args)
|
||||
{
|
||||
wistd::invoke(wistd::forward<TArgs>(args)...);
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
// Some RPC exceptions are already HRESULTs. Others are in the regular Win32
|
||||
// error space. If the incoming exception code isn't an HRESULT, wrap it.
|
||||
constexpr HRESULT map_rpc_exception(DWORD code)
|
||||
{
|
||||
return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code);
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/** Invokes an RPC method, mapping structured exceptions to HRESULTs
|
||||
Failures encountered by the RPC infrastructure (such as server crashes, authentication
|
||||
errors, client parameter issues, etc.) are emitted by raising a structured exception from
|
||||
within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept,
|
||||
RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual
|
||||
flow control machinery to use.
|
||||
|
||||
Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates
|
||||
the result of the _work_. HRESULTs returned by a successful completion of the _call_ are
|
||||
returned as-is.
|
||||
|
||||
RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_
|
||||
completes successfully.
|
||||
|
||||
For example, consider an RPC interface method defined in idl as:
|
||||
~~~
|
||||
HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state);
|
||||
~~~
|
||||
To call this method, use:
|
||||
~~~
|
||||
wil::unique_rpc_binding binding = // typically gotten elsewhere;
|
||||
wil::unique_midl_ptr<KittenState> state;
|
||||
HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put());
|
||||
RETURN_IF_FAILED(hr);
|
||||
~~~
|
||||
*/
|
||||
template <typename... TCall> HRESULT invoke_rpc_nothrow(TCall &&...args) WI_NOEXCEPT
|
||||
{
|
||||
RpcTryExcept
|
||||
{
|
||||
// Note: this helper type can be removed with C++17 enabled via
|
||||
// 'if constexpr(wistd::is_same_v<void, result_t>)'
|
||||
using result_t = typename wistd::__invoke_of<TCall...>::type;
|
||||
RETURN_IF_FAILED(details::call_adapter<result_t>::call(wistd::forward<TCall>(args)...));
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
// Some RPC exceptions are already HRESULTs. Others are in the regular Win32
|
||||
// error space. If the incoming exception code isn't an HRESULT, wrap it.
|
||||
constexpr HRESULT map_rpc_exception(DWORD code)
|
||||
{
|
||||
return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code);
|
||||
}
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/** Invokes an RPC method, mapping structured exceptions to HRESULTs
|
||||
Failures encountered by the RPC infrastructure (such as server crashes, authentication
|
||||
errors, client parameter issues, etc.) are emitted by raising a structured exception from
|
||||
within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept,
|
||||
RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual
|
||||
flow control machinery to use.
|
||||
|
||||
Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates
|
||||
the result of the _work_. HRESULTs returned by a successful completion of the _call_ are
|
||||
returned as-is.
|
||||
|
||||
RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_
|
||||
completes successfully.
|
||||
|
||||
For example, consider an RPC interface method defined in idl as:
|
||||
~~~
|
||||
HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state);
|
||||
~~~
|
||||
To call this method, use:
|
||||
~~~
|
||||
wil::unique_rpc_binding binding = // typically gotten elsewhere;
|
||||
wil::unique_midl_ptr<KittenState> state;
|
||||
HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put());
|
||||
RETURN_IF_FAILED(hr);
|
||||
~~~
|
||||
*/
|
||||
template <typename... TCall>
|
||||
HRESULT invoke_rpc_nothrow(TCall&&... args) WI_NOEXCEPT
|
||||
{
|
||||
RpcTryExcept
|
||||
{
|
||||
// Note: this helper type can be removed with C++17 enabled via
|
||||
// 'if constexpr(wistd::is_same_v<void, result_t>)'
|
||||
using result_t = typename wistd::__invoke_of<TCall...>::type;
|
||||
RETURN_IF_FAILED(details::call_adapter<result_t>::call(wistd::forward<TCall>(args)...));
|
||||
return S_OK;
|
||||
}
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
RETURN_HR(details::map_rpc_exception(RpcExceptionCode()));
|
||||
}
|
||||
RpcEndExcept
|
||||
}
|
||||
|
||||
/** Invokes an RPC method, mapping structured exceptions to HRESULTs
|
||||
Failures encountered by the RPC infrastructure (such as server crashes, authentication
|
||||
errors, client parameter issues, etc.) are emitted by raising a structured exception from
|
||||
within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept,
|
||||
RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual
|
||||
flow control machinery to use.
|
||||
|
||||
Some RPC methods return results (such as a state enumeration or other value) directly in
|
||||
their signature. This adapter writes that result into a caller-provided object then
|
||||
returns S_OK.
|
||||
|
||||
For example, consider an RPC interface method defined in idl as:
|
||||
~~~
|
||||
GUID GetKittenId([in, ref, string] const wchar_t* name);
|
||||
~~~
|
||||
To call this method, use:
|
||||
~~~
|
||||
wil::unique_rpc_binding binding = // typically gotten elsewhere;
|
||||
GUID id;
|
||||
HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy");
|
||||
RETURN_IF_FAILED(hr);
|
||||
~~~
|
||||
*/
|
||||
template <typename TResult, typename... TCall>
|
||||
HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT
|
||||
{
|
||||
RpcTryExcept
|
||||
{
|
||||
result = wistd::invoke(wistd::forward<TCall>(args)...);
|
||||
return S_OK;
|
||||
}
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
RETURN_HR(details::map_rpc_exception(RpcExceptionCode()));
|
||||
}
|
||||
RpcEndExcept
|
||||
}
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Provides an adapter around calling the context-handle-close method on an
|
||||
// RPC interface, which itself is an RPC call.
|
||||
template <typename TStorage, typename close_fn_t, close_fn_t close_fn>
|
||||
struct rpc_closer_t
|
||||
{
|
||||
static void Close(TStorage arg) WI_NOEXCEPT
|
||||
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<FOO_CONTEXT, decltype(&CloseFoo), CloseFoo>;
|
||||
unique_foo_context context;
|
||||
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put()));
|
||||
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get()));
|
||||
context.reset();
|
||||
@endcode
|
||||
*/
|
||||
template <typename TContext, typename close_fn_t, close_fn_t close_fn>
|
||||
using unique_rpc_context_handle =
|
||||
unique_any<TContext, decltype(&details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close), details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close>;
|
||||
Some RPC methods return results (such as a state enumeration or other value) directly in
|
||||
their signature. This adapter writes that result into a caller-provided object then
|
||||
returns S_OK.
|
||||
|
||||
For example, consider an RPC interface method defined in idl as:
|
||||
~~~
|
||||
GUID GetKittenId([in, ref, string] const wchar_t* name);
|
||||
~~~
|
||||
To call this method, use:
|
||||
~~~
|
||||
wil::unique_rpc_binding binding = // typically gotten elsewhere;
|
||||
GUID id;
|
||||
HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy");
|
||||
RETURN_IF_FAILED(hr);
|
||||
~~~
|
||||
*/
|
||||
template <typename TResult, typename... TCall>
|
||||
HRESULT invoke_rpc_result_nothrow(TResult &result, TCall &&...args) WI_NOEXCEPT
|
||||
{
|
||||
RpcTryExcept
|
||||
{
|
||||
result = wistd::invoke(wistd::forward<TCall>(args)...);
|
||||
return S_OK;
|
||||
}
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
RETURN_HR(details::map_rpc_exception(RpcExceptionCode()));
|
||||
}
|
||||
RpcEndExcept
|
||||
}
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Provides an adapter around calling the context-handle-close method on an
|
||||
// RPC interface, which itself is an RPC call.
|
||||
template <typename TStorage, typename close_fn_t, close_fn_t close_fn> struct rpc_closer_t
|
||||
{
|
||||
static void Close(TStorage arg) WI_NOEXCEPT
|
||||
{
|
||||
LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg));
|
||||
}
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
/** Manages explicit RPC context handles
|
||||
Explicit RPC context handles are used in many RPC interfaces. Most interfaces with
|
||||
context handles have an explicit `FooClose([in, out] CONTEXT*)` method that lets
|
||||
the server close out the context handle. As the close method itself is an RPC call,
|
||||
it can fail and raise a structured exception.
|
||||
|
||||
This type routes the context-handle-specific `Close` call through the `invoke_rpc_nothrow`
|
||||
helper, ensuring correct cleanup and lifecycle management.
|
||||
@code
|
||||
// Assume the interface has two methods:
|
||||
// HRESULT OpenFoo([in] handle_t binding, [out] FOO_CONTEXT*);
|
||||
// HRESULT UseFoo([in] FOO_CONTEXT context;
|
||||
// void CloseFoo([in, out] PFOO_CONTEXT);
|
||||
using unique_foo_context = wil::unique_rpc_context_handle<FOO_CONTEXT, decltype(&CloseFoo), CloseFoo>;
|
||||
unique_foo_context context;
|
||||
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put()));
|
||||
RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get()));
|
||||
context.reset();
|
||||
@endcode
|
||||
*/
|
||||
template <typename TContext, typename close_fn_t, close_fn_t close_fn>
|
||||
using unique_rpc_context_handle =
|
||||
unique_any<TContext, decltype(&details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close),
|
||||
details::rpc_closer_t<TContext, close_fn_t, close_fn>::Close>;
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
|
||||
See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_
|
||||
and those returned by the _method_ are mapped to HRESULTs and thrown inside a
|
||||
wil::ResultException. Using the example RPC method provided above:
|
||||
@code
|
||||
wil::unique_midl_ptr<KittenState> state;
|
||||
wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put());
|
||||
// use 'state'
|
||||
@endcode
|
||||
*/
|
||||
template <typename... TCall>
|
||||
void invoke_rpc(TCall&&... args)
|
||||
{
|
||||
THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward<TCall>(args)...));
|
||||
}
|
||||
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
|
||||
See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_
|
||||
and those returned by the _method_ are mapped to HRESULTs and thrown inside a
|
||||
wil::ResultException. Using the example RPC method provided above:
|
||||
@code
|
||||
wil::unique_midl_ptr<KittenState> state;
|
||||
wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put());
|
||||
// use 'state'
|
||||
@endcode
|
||||
*/
|
||||
template <typename... TCall> void invoke_rpc(TCall &&...args)
|
||||
{
|
||||
THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward<TCall>(args)...));
|
||||
}
|
||||
|
||||
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
|
||||
See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the
|
||||
_call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the
|
||||
example RPC method provided above:
|
||||
@code
|
||||
GUID id = wil::invoke_rpc_result(GetKittenId, binding.get());
|
||||
// use 'id'
|
||||
@endcode
|
||||
*/
|
||||
template <typename... TCall>
|
||||
auto invoke_rpc_result(TCall&&... args)
|
||||
{
|
||||
using result_t = typename wistd::__invoke_of<TCall...>::type;
|
||||
result_t result{};
|
||||
THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward<TCall>(args)...));
|
||||
return result;
|
||||
}
|
||||
/** Invokes an RPC method, mapping structured exceptions to C++ exceptions
|
||||
See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the
|
||||
_call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the
|
||||
example RPC method provided above:
|
||||
@code
|
||||
GUID id = wil::invoke_rpc_result(GetKittenId, binding.get());
|
||||
// use 'id'
|
||||
@endcode
|
||||
*/
|
||||
template <typename... TCall> auto invoke_rpc_result(TCall &&...args)
|
||||
{
|
||||
using result_t = typename wistd::__invoke_of<TCall...>::type;
|
||||
result_t result{};
|
||||
THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward<TCall>(args)...));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
} // namespace wil
|
||||
|
||||
|
||||
@@ -14,388 +14,354 @@
|
||||
#define __WIL_SAFECAST_INCLUDED
|
||||
|
||||
#include "result_macros.h"
|
||||
#include <intsafe.h>
|
||||
#include "wistd_config.h"
|
||||
#include "wistd_type_traits.h"
|
||||
#include <intsafe.h>
|
||||
|
||||
namespace wil
|
||||
{
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Default error case for undefined conversions in intsafe.h
|
||||
template <typename OldT, typename NewT>
|
||||
constexpr wistd::nullptr_t intsafe_conversion = nullptr;
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Default error case for undefined conversions in intsafe.h
|
||||
template <typename OldT, typename NewT> constexpr wistd::nullptr_t intsafe_conversion = nullptr;
|
||||
|
||||
// is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known
|
||||
// safe conversions can be handled by static_cast, this includes conversions between the same
|
||||
// type, when the new type is larger than the old type but is not a signed to unsigned
|
||||
// conversion, and when the two types are the same size and signed/unsigned. All other
|
||||
// conversions will be assumed to be potentially unsafe, and the conversion must be handled
|
||||
// by intsafe and checked.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_known_safe_static_cast_v =
|
||||
(sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v<OldT> && wistd::is_unsigned_v<NewT>)) ||
|
||||
(sizeof(NewT) == sizeof(OldT) &&
|
||||
((wistd::is_signed_v<NewT> && wistd::is_signed_v<OldT>) || (wistd::is_unsigned_v<NewT> && wistd::is_unsigned_v<OldT>)));
|
||||
// is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known
|
||||
// safe conversions can be handled by static_cast, this includes conversions between the same
|
||||
// type, when the new type is larger than the old type but is not a signed to unsigned
|
||||
// conversion, and when the two types are the same size and signed/unsigned. All other
|
||||
// conversions will be assumed to be potentially unsafe, and the conversion must be handled
|
||||
// by intsafe and checked.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_known_safe_static_cast_v =
|
||||
(sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v<OldT> && wistd::is_unsigned_v<NewT>)) ||
|
||||
(sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v<NewT> && wistd::is_signed_v<OldT>) ||
|
||||
(wistd::is_unsigned_v<NewT> && wistd::is_unsigned_v<OldT>)));
|
||||
|
||||
// Helper template to determine that NewT and OldT are both integral types. The safe_cast
|
||||
// operation only supports conversions between integral types.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool both_integral_v = wistd::is_integral<NewT>::value && wistd::is_integral<OldT>::value;
|
||||
// Helper template to determine that NewT and OldT are both integral types. The safe_cast
|
||||
// operation only supports conversions between integral types.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool both_integral_v = wistd::is_integral<NewT>::value && wistd::is_integral<OldT>::value;
|
||||
|
||||
// Helper template to determine that the cast from OldT to NewT is going to sign extend the
|
||||
// value. This is only true when the size of NewT is larger than OldT and OldT is signed.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_sign_extending_cast_v =
|
||||
(sizeof(NewT) >= sizeof(OldT)) && both_integral_v<NewT, OldT> && wistd::is_signed_v<OldT>;
|
||||
// Helper template to determine that the cast from OldT to NewT is going to sign extend the
|
||||
// value. This is only true when the size of NewT is larger than OldT and OldT is signed.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_sign_extending_cast_v =
|
||||
(sizeof(NewT) >= sizeof(OldT)) && both_integral_v<NewT, OldT> && wistd::is_signed_v<OldT>;
|
||||
|
||||
// Note on native wchar_t (__wchar_t):
|
||||
// Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is
|
||||
// typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of
|
||||
// support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an
|
||||
// unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and
|
||||
// share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast
|
||||
// to a native wchar_t.
|
||||
// Note on native wchar_t (__wchar_t):
|
||||
// Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as
|
||||
// wchar_t is typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native
|
||||
// type, the lack of support for native wchar_t in intsafe.h becomes an issue. To work around this, we
|
||||
// treat native wchar_t as an unsigned short when passing it to intsafe.h, because the two on the Windows
|
||||
// platform are the same size and share the same range according to MSDN. If the cast is to a native
|
||||
// wchar_t, the result from intsafe.h is cast to a native wchar_t.
|
||||
|
||||
// Intsafe does not have a defined conversion for native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool neither_native_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
|
||||
// Intsafe does not have a defined conversion for native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool neither_native_wchar_v =
|
||||
!wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
|
||||
|
||||
// Check to see if the cast is a conversion to native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_cast_to_wchar_v = wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
|
||||
// Check to see if the cast is a conversion to native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_cast_to_wchar_v =
|
||||
wistd::is_same<NewT, __wchar_t>::value && !wistd::is_same<OldT, __wchar_t>::value;
|
||||
|
||||
// Check to see if the cast is a conversion from native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_cast_from_wchar_v = !wistd::is_same<NewT, __wchar_t>::value && wistd::is_same<OldT, __wchar_t>::value;
|
||||
// Check to see if the cast is a conversion from native wchar_t
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_cast_from_wchar_v =
|
||||
!wistd::is_same<NewT, __wchar_t>::value && wistd::is_same<OldT, __wchar_t>::value;
|
||||
|
||||
// Validate the conversion to be performed has a defined mapping to an intsafe conversion
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_intsafe_cast_v = intsafe_conversion<OldT, NewT> != nullptr;
|
||||
// Validate the conversion to be performed has a defined mapping to an intsafe conversion
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_intsafe_cast_v = intsafe_conversion<OldT, NewT> != nullptr;
|
||||
|
||||
// True when the conversion is between integral types and can be handled by static_cast
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_safe_static_cast_v = both_integral_v<NewT, OldT> && is_known_safe_static_cast_v<NewT, OldT>;
|
||||
// True when the conversion is between integral types and can be handled by static_cast
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_safe_static_cast_v =
|
||||
both_integral_v<NewT, OldT> && is_known_safe_static_cast_v<NewT, OldT>;
|
||||
|
||||
// True when the conversion is between integral types, does not involve native wchar, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_no_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && neither_native_wchar_v<NewT, OldT> &&
|
||||
is_supported_intsafe_cast_v<NewT, OldT>;
|
||||
// True when the conversion is between integral types, does not involve native wchar, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_no_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> &&
|
||||
neither_native_wchar_v<NewT, OldT> && is_supported_intsafe_cast_v<NewT, OldT>;
|
||||
|
||||
// True when the conversion is between integral types, is a cast to native wchar_t, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_to_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && is_cast_to_wchar_v<NewT, OldT> &&
|
||||
is_supported_intsafe_cast_v<unsigned short, OldT>;
|
||||
// True when the conversion is between integral types, is a cast to native wchar_t, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_to_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && is_cast_to_wchar_v<NewT, OldT> &&
|
||||
is_supported_intsafe_cast_v<unsigned short, OldT>;
|
||||
|
||||
// True when the conversion is between integral types, is a cast from native wchar_t, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_from_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> && is_cast_from_wchar_v<NewT, OldT> &&
|
||||
is_supported_intsafe_cast_v<NewT, unsigned short>;
|
||||
// True when the conversion is between integral types, is a cast from native wchar_t, has
|
||||
// a mapped intsafe conversion, and is unsafe.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_from_wchar_v =
|
||||
both_integral_v<NewT, OldT> && !is_known_safe_static_cast_v<NewT, OldT> &&
|
||||
is_cast_from_wchar_v<NewT, OldT> && is_supported_intsafe_cast_v<NewT, unsigned short>;
|
||||
|
||||
// True when the conversion is supported and unsafe, and may or may not involve
|
||||
// native wchar_t.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_v =
|
||||
is_supported_unsafe_cast_no_wchar_v<NewT, OldT> || is_supported_unsafe_cast_to_wchar_v<NewT, OldT> ||
|
||||
is_supported_unsafe_cast_from_wchar_v<NewT, OldT>;
|
||||
// True when the conversion is supported and unsafe, and may or may not involve
|
||||
// native wchar_t.
|
||||
template <typename NewT, typename OldT>
|
||||
constexpr bool is_supported_unsafe_cast_v =
|
||||
is_supported_unsafe_cast_no_wchar_v<NewT, OldT> || is_supported_unsafe_cast_to_wchar_v<NewT, OldT> ||
|
||||
is_supported_unsafe_cast_from_wchar_v<NewT, OldT>;
|
||||
|
||||
// True when T is any one of the primitive types that the variably sized types are defined as.
|
||||
template <typename T>
|
||||
constexpr bool is_potentially_variably_sized_type_v =
|
||||
wistd::is_same<T, int>::value || wistd::is_same<T, unsigned int>::value || wistd::is_same<T, long>::value ||
|
||||
wistd::is_same<T, unsigned long>::value || wistd::is_same<T, __int64>::value || wistd::is_same<T, unsigned __int64>::value;
|
||||
// True when T is any one of the primitive types that the variably sized types are defined as.
|
||||
template <typename T>
|
||||
constexpr bool is_potentially_variably_sized_type_v =
|
||||
wistd::is_same<T, int>::value || wistd::is_same<T, unsigned int>::value || wistd::is_same<T, long>::value ||
|
||||
wistd::is_same<T, unsigned long>::value || wistd::is_same<T, __int64>::value ||
|
||||
wistd::is_same<T, unsigned __int64>::value;
|
||||
|
||||
// True when either type is potentially variably sized (e.g. size_t, ptrdiff_t)
|
||||
template <typename OldT, typename NewT>
|
||||
constexpr bool is_potentially_variably_sized_cast_v =
|
||||
is_potentially_variably_sized_type_v<OldT> || is_potentially_variably_sized_type_v<NewT>;
|
||||
// True when either type is potentially variably sized (e.g. size_t, ptrdiff_t)
|
||||
template <typename OldT, typename NewT>
|
||||
constexpr bool is_potentially_variably_sized_cast_v =
|
||||
is_potentially_variably_sized_type_v<OldT> || is_potentially_variably_sized_type_v<NewT>;
|
||||
|
||||
// Mappings of all conversions defined in intsafe.h to intsafe_conversion
|
||||
// Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve
|
||||
// to the base types. The base types are used since they do not vary based on architecture.
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, char> = IntToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, short> = IntToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, char> = LongToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, int> = LongToInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, short> = LongToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, char> = ShortToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
// Mappings of all conversions defined in intsafe.h to intsafe_conversion
|
||||
// Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve
|
||||
// to the base types. The base types are used since they do not vary based on architecture.
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, char> = LongLongToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, int> = LongLongToInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, long> = LongLongToLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, short> = LongLongToShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, char> = IntToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, short> = IntToShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, signed char> = IntToInt8;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned __int64> = IntToULongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned char> = IntToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned int> = IntToUInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned long> = IntToULong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<int, unsigned short> = IntToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, char> = LongToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, int> = LongToInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, short> = LongToShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, signed char> = LongToInt8;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned __int64> = LongToULongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned char> = LongToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned int> = LongToUInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned long> = LongToULong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<long, unsigned short> = LongToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, char> = ShortToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, signed char> = ShortToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned __int64> = ShortToULongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned char> = ShortToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned int> = ShortToUInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned long> = ShortToULong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<short, unsigned short> = ShortToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned __int64> = Int8ToULongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned char> = Int8ToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned int> = Int8ToUInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned long> = Int8ToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<signed char, unsigned short> = Int8ToUShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, __int64> = ULongLongToLongLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, char> = ULongLongToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, int> = ULongLongToInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, long> = ULongLongToLong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, short> = ULongLongToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, signed char> = ULongLongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned char> = ULongLongToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned int> = ULongLongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned long> = ULongLongToULong;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned __int64, unsigned short> = ULongLongToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, char> = UInt8ToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned char, signed char> = UIntToInt8;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, char> = UIntToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, int> = UIntToInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, long> = UIntToLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, short> = UIntToShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, signed char> = UIntToInt8;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned char> = UIntToUChar;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned int, unsigned short> = UIntToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, char> = ULongToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, int> = ULongToInt;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, long> = ULongToLong;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, short> = ULongToShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, signed char> = ULongToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned char> = ULongToUChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned int> = ULongToUInt;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned long, unsigned short> = ULongToUShort;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, char> = UShortToChar;
|
||||
template <> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, short> = UShortToShort;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, signed char> = UShortToInt8;
|
||||
template <>
|
||||
__WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<unsigned short, unsigned char> = UShortToUChar;
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
FAIL_FAST_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
FAIL_FAST_IF_FAILED(
|
||||
(details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
unsigned short newVar;
|
||||
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
|
||||
return static_cast<__wchar_t>(newVar);
|
||||
}
|
||||
// Unsafe conversion where failure results in fail fast.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
unsigned short newVar;
|
||||
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
|
||||
return static_cast<__wchar_t>(newVar);
|
||||
}
|
||||
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_failfast(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
NewT newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
|
||||
return newVar;
|
||||
}
|
||||
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
unsigned short newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
|
||||
return static_cast<__wchar_t>(newVar);
|
||||
}
|
||||
// Unsafe conversion where failure results in a thrown exception.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
unsigned short newVar;
|
||||
THROW_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
|
||||
return static_cast<__wchar_t>(newVar);
|
||||
}
|
||||
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_nothrow(const OldT /*var*/)
|
||||
{
|
||||
static_assert(!wistd::is_same_v<NewT, NewT>, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead");
|
||||
}
|
||||
// This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_nothrow(const OldT /*var*/)
|
||||
{
|
||||
static_assert(!wistd::is_same_v<NewT, NewT>,
|
||||
"This cast has the potential to fail, use the two parameter safe_cast_nothrow instead");
|
||||
}
|
||||
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_nothrow(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
// This conversion is always safe, therefore a static_cast is fine.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_cast_nothrow(const OldT var)
|
||||
{
|
||||
return static_cast<NewT>(var);
|
||||
}
|
||||
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<OldT, NewT>(var, newTResult);
|
||||
}
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<OldT, NewT>(var, newTResult);
|
||||
}
|
||||
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), newTResult);
|
||||
}
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), newTResult);
|
||||
}
|
||||
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<OldT, unsigned short>(var, reinterpret_cast<unsigned short*>(newTResult));
|
||||
}
|
||||
// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult)
|
||||
{
|
||||
return details::intsafe_conversion<OldT, unsigned short>(var, reinterpret_cast<unsigned short *>(newTResult));
|
||||
}
|
||||
|
||||
// This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion
|
||||
// does not involve a variably sized type, then the compilation will fail and say the single parameter version
|
||||
// of safe_cast_nothrow should be used instead.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
|
||||
{
|
||||
static_assert(
|
||||
details::is_potentially_variably_sized_cast_v<OldT, NewT>,
|
||||
"This cast is always safe; use safe_cast_nothrow<T>(value) to avoid unnecessary error handling.");
|
||||
*newTResult = static_cast<NewT>(var);
|
||||
return S_OK;
|
||||
}
|
||||
// This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion
|
||||
// does not involve a variably sized type, then the compilation will fail and say the single parameter version
|
||||
// of safe_cast_nothrow should be used instead.
|
||||
template <typename NewT, typename OldT,
|
||||
wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
|
||||
HRESULT safe_cast_nothrow(const OldT var, NewT *newTResult)
|
||||
{
|
||||
static_assert(details::is_potentially_variably_sized_cast_v<OldT, NewT>,
|
||||
"This cast is always safe; use safe_cast_nothrow<T>(value) to avoid unnecessary error handling.");
|
||||
*newTResult = static_cast<NewT>(var);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// This conversion takes a signed integer value and grows it with the upper bits set to zero. This is
|
||||
// useful when the resulting value is cast to a pointer type as it prevents the upper bits from being fill
|
||||
// which would adjust the pointed-to address.
|
||||
//
|
||||
// For example:
|
||||
// wil::safe_zero_extending_cast<ULONG_PTR>(-1)
|
||||
// will return 0x00000000`FFFFFFFF on a 64-bit system.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_sign_extending_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_zero_extending_cast(const OldT var)
|
||||
{
|
||||
// The first cast is to an unsigned type of the same size as the original. The second cast is to the
|
||||
// larger type. Being an unsigned cast, the upper bits are zeroed out.
|
||||
using unsigned_old_t = wistd::make_unsigned_t<OldT>;
|
||||
return static_cast<NewT>(static_cast<unsigned_old_t>(var));
|
||||
}
|
||||
// This conversion takes a signed integer value and grows it with the upper bits set to zero. This is
|
||||
// useful when the resulting value is cast to a pointer type as it prevents the upper bits from being fill
|
||||
// which would adjust the pointed-to address.
|
||||
//
|
||||
// For example:
|
||||
// wil::safe_zero_extending_cast<ULONG_PTR>(-1)
|
||||
// will return 0x00000000`FFFFFFFF on a 64-bit system.
|
||||
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_sign_extending_cast_v<NewT, OldT>, int> = 0>
|
||||
NewT safe_zero_extending_cast(const OldT var)
|
||||
{
|
||||
// The first cast is to an unsigned type of the same size as the original. The second cast is to the
|
||||
// larger type. Being an unsigned cast, the upper bits are zeroed out.
|
||||
using unsigned_old_t = wistd::make_unsigned_t<OldT>;
|
||||
return static_cast<NewT>(static_cast<unsigned_old_t>(var));
|
||||
}
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_SAFECAST_INCLUDED
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#include "resource.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#if (__WI_LIBCPP_STD_VER >= 17) && WI_HAS_INCLUDE(<string_view>, 1) // Assume present if C++17
|
||||
#include <string_view>
|
||||
#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 <typename T>
|
||||
struct secure_allocator : public std::allocator<T>
|
||||
{
|
||||
template <typename Other>
|
||||
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 <typename T> struct secure_allocator : public std::allocator<T>
|
||||
{
|
||||
using other = secure_allocator<Other>;
|
||||
template <typename Other> struct rebind
|
||||
{
|
||||
using other = secure_allocator<Other>;
|
||||
};
|
||||
|
||||
secure_allocator() : std::allocator<T>()
|
||||
{
|
||||
}
|
||||
|
||||
~secure_allocator() = default;
|
||||
|
||||
secure_allocator(const secure_allocator &a) : std::allocator<T>(a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class U> secure_allocator(const secure_allocator<U> &a) : std::allocator<T>(a)
|
||||
{
|
||||
}
|
||||
|
||||
T *allocate(size_t n)
|
||||
{
|
||||
return std::allocator<T>::allocate(n);
|
||||
}
|
||||
|
||||
void deallocate(T *p, size_t n)
|
||||
{
|
||||
SecureZeroMemory(p, sizeof(T) * n);
|
||||
std::allocator<T>::deallocate(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
secure_allocator() : std::allocator<T>()
|
||||
//! `wil::secure_vector` will be securely zeroed before deallocation.
|
||||
template <typename Type> using secure_vector = std::vector<Type, secure_allocator<Type>>;
|
||||
//! `wil::secure_wstring` will be securely zeroed before deallocation.
|
||||
using secure_wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>, wil::secure_allocator<wchar_t>>;
|
||||
//! `wil::secure_string` will be securely zeroed before deallocation.
|
||||
using secure_string = std::basic_string<char, std::char_traits<char>, wil::secure_allocator<char>>;
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <> struct string_maker<std::wstring>
|
||||
{
|
||||
HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT
|
||||
try
|
||||
{
|
||||
m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0');
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
wchar_t *buffer()
|
||||
{
|
||||
return &m_value[0];
|
||||
}
|
||||
|
||||
HRESULT trim_at_existing_null(size_t length)
|
||||
{
|
||||
m_value.erase(length);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::wstring release()
|
||||
{
|
||||
return std::wstring(std::move(m_value));
|
||||
}
|
||||
|
||||
static PCWSTR get(const std::wstring &value)
|
||||
{
|
||||
return value.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring m_value;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
// str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
|
||||
// This is the overload for std::wstring. Other overloads available in resource.h.
|
||||
inline PCWSTR str_raw_ptr(const std::wstring &str)
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
~secure_allocator() = default;
|
||||
|
||||
secure_allocator(const secure_allocator& a) : std::allocator<T>(a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class U>
|
||||
secure_allocator(const secure_allocator<U>& a) : std::allocator<T>(a)
|
||||
{
|
||||
}
|
||||
|
||||
T* allocate(size_t n)
|
||||
{
|
||||
return std::allocator<T>::allocate(n);
|
||||
}
|
||||
|
||||
void deallocate(T* p, size_t n)
|
||||
{
|
||||
SecureZeroMemory(p, sizeof(T) * n);
|
||||
std::allocator<T>::deallocate(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
//! `wil::secure_vector` will be securely zeroed before deallocation.
|
||||
template <typename Type>
|
||||
using secure_vector = std::vector<Type, secure_allocator<Type>>;
|
||||
//! `wil::secure_wstring` will be securely zeroed before deallocation.
|
||||
using secure_wstring = std::basic_string<wchar_t, std::char_traits<wchar_t>, wil::secure_allocator<wchar_t>>;
|
||||
//! `wil::secure_string` will be securely zeroed before deallocation.
|
||||
using secure_string = std::basic_string<char, std::char_traits<char>, wil::secure_allocator<char>>;
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <>
|
||||
struct string_maker<std::wstring>
|
||||
{
|
||||
HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT
|
||||
try
|
||||
{
|
||||
m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0');
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
wchar_t* buffer()
|
||||
{
|
||||
return &m_value[0];
|
||||
}
|
||||
|
||||
HRESULT trim_at_existing_null(size_t length)
|
||||
{
|
||||
m_value.erase(length);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::wstring release()
|
||||
{
|
||||
return std::wstring(std::move(m_value));
|
||||
}
|
||||
|
||||
static PCWSTR get(const std::wstring& value)
|
||||
{
|
||||
return value.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring m_value;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
// str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer.
|
||||
// This is the overload for std::wstring. Other overloads available in resource.h.
|
||||
inline PCWSTR str_raw_ptr(const std::wstring& str)
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
#if __cpp_lib_string_view >= 201606L
|
||||
/**
|
||||
zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty).
|
||||
* zstring_view can be used for storing string literals without "forgetting" the length or that it is nul-terminated.
|
||||
* A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a nul-terminated
|
||||
string_view as a plain string view.
|
||||
* A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated.
|
||||
*/
|
||||
template <class TChar>
|
||||
class basic_zstring_view : public std::basic_string_view<TChar>
|
||||
{
|
||||
using size_type = typename std::basic_string_view<TChar>::size_type;
|
||||
|
||||
public:
|
||||
constexpr basic_zstring_view() noexcept = default;
|
||||
constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default;
|
||||
constexpr basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default;
|
||||
|
||||
constexpr basic_zstring_view(const TChar* pStringData, size_type stringLength) noexcept :
|
||||
std::basic_string_view<TChar>(pStringData, stringLength)
|
||||
/**
|
||||
zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless
|
||||
empty).
|
||||
* zstring_view can be used for storing string literals without "forgetting" the length or that it is
|
||||
nul-terminated.
|
||||
* A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a
|
||||
nul-terminated string_view as a plain string view.
|
||||
* A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated.
|
||||
*/
|
||||
template <class TChar> class basic_zstring_view : public std::basic_string_view<TChar>
|
||||
{
|
||||
if (pStringData[stringLength] != 0)
|
||||
using size_type = typename std::basic_string_view<TChar>::size_type;
|
||||
|
||||
public:
|
||||
constexpr basic_zstring_view() noexcept = default;
|
||||
constexpr basic_zstring_view(const basic_zstring_view &) noexcept = default;
|
||||
constexpr basic_zstring_view &operator=(const basic_zstring_view &) noexcept = default;
|
||||
|
||||
constexpr basic_zstring_view(const TChar *pStringData, size_type stringLength) noexcept
|
||||
: std::basic_string_view<TChar>(pStringData, stringLength)
|
||||
{
|
||||
WI_STL_FAIL_FAST_IF(true);
|
||||
if (pStringData[stringLength] != 0)
|
||||
{
|
||||
WI_STL_FAIL_FAST_IF(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t stringArrayLength>
|
||||
constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept :
|
||||
std::basic_string_view<TChar>(&stringArray[0], length_n(&stringArray[0], stringArrayLength))
|
||||
{
|
||||
}
|
||||
|
||||
// Construct from nul-terminated char ptr. To prevent this from overshadowing array construction,
|
||||
// we disable this constructor if the value is an array (including string literal).
|
||||
template <typename TPtr, std::enable_if_t<std::is_convertible<TPtr, const TChar*>::value && !std::is_array<TPtr>::value>* = nullptr>
|
||||
constexpr basic_zstring_view(TPtr&& pStr) noexcept : std::basic_string_view<TChar>(std::forward<TPtr>(pStr))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr basic_zstring_view(const std::basic_string<TChar>& str) noexcept :
|
||||
std::basic_string_view<TChar>(&str[0], str.size())
|
||||
{
|
||||
}
|
||||
|
||||
// basic_string_view [] precondition won't let us read view[view.size()]; so we define our own.
|
||||
WI_NODISCARD constexpr const TChar& operator[](size_type idx) const noexcept
|
||||
{
|
||||
WI_ASSERT(idx <= this->size() && this->data() != nullptr);
|
||||
return this->data()[idx];
|
||||
}
|
||||
|
||||
WI_NODISCARD constexpr const TChar* c_str() const noexcept
|
||||
{
|
||||
WI_ASSERT(this->data() == nullptr || this->data()[this->size()] == 0);
|
||||
return this->data();
|
||||
}
|
||||
|
||||
private:
|
||||
// Bounds-checked version of char_traits::length, like strnlen. Requires that the input contains a null terminator.
|
||||
static constexpr size_type length_n(_In_reads_opt_(buf_size) const TChar* str, size_type buf_size) noexcept
|
||||
{
|
||||
const std::basic_string_view<TChar> view(str, buf_size);
|
||||
auto pos = view.find_first_of(TChar());
|
||||
if (pos == view.npos)
|
||||
template <size_t stringArrayLength>
|
||||
constexpr basic_zstring_view(const TChar (&stringArray)[stringArrayLength]) noexcept
|
||||
: std::basic_string_view<TChar>(&stringArray[0], length_n(&stringArray[0], stringArrayLength))
|
||||
{
|
||||
WI_STL_FAIL_FAST_IF(true);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// The following basic_string_view methods must not be allowed because they break the nul-termination.
|
||||
using std::basic_string_view<TChar>::swap;
|
||||
using std::basic_string_view<TChar>::remove_suffix;
|
||||
};
|
||||
// Construct from nul-terminated char ptr. To prevent this from overshadowing array construction,
|
||||
// we disable this constructor if the value is an array (including string literal).
|
||||
template <typename TPtr, std::enable_if_t<std::is_convertible<TPtr, const TChar *>::value &&
|
||||
!std::is_array<TPtr>::value> * = nullptr>
|
||||
constexpr basic_zstring_view(TPtr &&pStr) noexcept : std::basic_string_view<TChar>(std::forward<TPtr>(pStr))
|
||||
{
|
||||
}
|
||||
|
||||
using zstring_view = basic_zstring_view<char>;
|
||||
using zwstring_view = basic_zstring_view<wchar_t>;
|
||||
constexpr basic_zstring_view(const std::basic_string<TChar> &str) noexcept
|
||||
: std::basic_string_view<TChar>(&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<TChar> view(str, buf_size);
|
||||
auto pos = view.find_first_of(TChar());
|
||||
if (pos == view.npos)
|
||||
{
|
||||
WI_STL_FAIL_FAST_IF(true);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// The following basic_string_view methods must not be allowed because they break the nul-termination.
|
||||
using std::basic_string_view<TChar>::swap;
|
||||
using std::basic_string_view<TChar>::remove_suffix;
|
||||
};
|
||||
|
||||
using zstring_view = basic_zstring_view<char>;
|
||||
using zwstring_view = basic_zstring_view<wchar_t>;
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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<FailureType::Return>(__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<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
|
||||
}
|
||||
#endif
|
||||
|
||||
__R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
||||
{
|
||||
__R_FN_LOCALS;
|
||||
return __WIN32_FROM_HRESULT(wil::details::ReportFailure_GetLastErrorHr<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
|
||||
}
|
||||
} // namespace details::__R_NS_NAME
|
||||
/// @endcond
|
||||
__R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
||||
{
|
||||
__R_FN_LOCALS;
|
||||
return __WIN32_FROM_HRESULT(
|
||||
wil::details::ReportFailure_GetLastErrorHr<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY));
|
||||
}
|
||||
} // namespace details::__R_NS_NAME
|
||||
/// @endcond
|
||||
} // namespace wil
|
||||
|
||||
#endif // __WIL_WIN32_RESULTMACROS_INCLUDED
|
||||
|
||||
@@ -19,71 +19,23 @@
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
namespace wil
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
template <typename T>
|
||||
struct always_false : wistd::false_type
|
||||
namespace details
|
||||
{
|
||||
};
|
||||
template <typename T> struct always_false : wistd::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename TCallback>
|
||||
BOOL __stdcall EnumWindowsCallbackNoThrow(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
auto pCallback = reinterpret_cast<TCallback*>(lParam);
|
||||
#if __cpp_if_constexpr >= 201606L
|
||||
using result_t = decltype((*pCallback)(hwnd));
|
||||
if constexpr (wistd::is_void_v<result_t>)
|
||||
template <typename TCallback> BOOL __stdcall EnumWindowsCallbackNoThrow(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
(*pCallback)(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
else if constexpr (wistd::is_same_v<result_t, HRESULT>)
|
||||
{
|
||||
// NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0
|
||||
return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE;
|
||||
}
|
||||
else if constexpr (std::is_same_v<result_t, bool>)
|
||||
{
|
||||
return (*pCallback)(hwnd) ? TRUE : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(details::always_false<TCallback>::value, "Callback must return void, bool, or HRESULT");
|
||||
}
|
||||
#else
|
||||
return (*pCallback)(hwnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename TEnumApi, typename TCallback>
|
||||
void DoEnumWindowsNoThrow(TEnumApi&& enumApi, TCallback&& callback) noexcept
|
||||
{
|
||||
enumApi(EnumWindowsCallbackNoThrow<TCallback>, reinterpret_cast<LPARAM>(&callback));
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template <typename TCallback>
|
||||
struct EnumWindowsCallbackData
|
||||
{
|
||||
std::exception_ptr exception;
|
||||
TCallback* pCallback;
|
||||
};
|
||||
|
||||
template <typename TCallback>
|
||||
BOOL __stdcall EnumWindowsCallback(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
auto pCallbackData = reinterpret_cast<EnumWindowsCallbackData<TCallback>*>(lParam);
|
||||
try
|
||||
{
|
||||
auto pCallback = pCallbackData->pCallback;
|
||||
auto pCallback = reinterpret_cast<TCallback *>(lParam);
|
||||
#if __cpp_if_constexpr >= 201606L
|
||||
using result_t = decltype((*pCallback)(hwnd));
|
||||
if constexpr (std::is_void_v<result_t>)
|
||||
if constexpr (wistd::is_void_v<result_t>)
|
||||
{
|
||||
(*pCallback)(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
else if constexpr (std::is_same_v<result_t, HRESULT>)
|
||||
else if constexpr (wistd::is_same_v<result_t, HRESULT>)
|
||||
{
|
||||
// NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0
|
||||
return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE;
|
||||
@@ -100,74 +52,114 @@ namespace details
|
||||
return (*pCallback)(hwnd);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
|
||||
template <typename TEnumApi, typename TCallback>
|
||||
void DoEnumWindowsNoThrow(TEnumApi &&enumApi, TCallback &&callback) noexcept
|
||||
{
|
||||
pCallbackData->exception = std::current_exception();
|
||||
return FALSE;
|
||||
enumApi(EnumWindowsCallbackNoThrow<TCallback>, reinterpret_cast<LPARAM>(&callback));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TEnumApi, typename TCallback>
|
||||
void DoEnumWindows(TEnumApi&& enumApi, TCallback&& callback)
|
||||
{
|
||||
EnumWindowsCallbackData<TCallback> callbackData = {nullptr, &callback};
|
||||
enumApi(EnumWindowsCallback<TCallback>, reinterpret_cast<LPARAM>(&callbackData));
|
||||
if (callbackData.exception)
|
||||
{
|
||||
std::rethrow_exception(callbackData.exception);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace details
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_window_nothrow(TCallback&& callback) noexcept
|
||||
{
|
||||
details::DoEnumWindowsNoThrow(&EnumWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_thread_window_nothrow(_In_ DWORD threadId, TCallback&& callback) noexcept
|
||||
{
|
||||
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumThreadWindows(threadId, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindowsNoThrow(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_child_window_nothrow(_In_ HWND hwndParent, TCallback&& callback) noexcept
|
||||
{
|
||||
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumChildWindows(hwndParent, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindowsNoThrow(boundEnumChildWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template <typename TCallback>
|
||||
void for_each_window(TCallback&& callback)
|
||||
{
|
||||
details::DoEnumWindows(&EnumWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
template <typename TCallback> struct EnumWindowsCallbackData
|
||||
{
|
||||
std::exception_ptr exception;
|
||||
TCallback *pCallback;
|
||||
};
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_thread_window(_In_ DWORD threadId, TCallback&& callback)
|
||||
{
|
||||
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumThreadWindows(threadId, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindows(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
template <typename TCallback> BOOL __stdcall EnumWindowsCallback(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
auto pCallbackData = reinterpret_cast<EnumWindowsCallbackData<TCallback> *>(lParam);
|
||||
try
|
||||
{
|
||||
auto pCallback = pCallbackData->pCallback;
|
||||
#if __cpp_if_constexpr >= 201606L
|
||||
using result_t = decltype((*pCallback)(hwnd));
|
||||
if constexpr (std::is_void_v<result_t>)
|
||||
{
|
||||
(*pCallback)(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
else if constexpr (std::is_same_v<result_t, HRESULT>)
|
||||
{
|
||||
// NB: this works for both HRESULT and NTSTATUS as both S_OK and ERROR_SUCCESS are 0
|
||||
return (S_OK == (*pCallback)(hwnd)) ? TRUE : FALSE;
|
||||
}
|
||||
else if constexpr (std::is_same_v<result_t, bool>)
|
||||
{
|
||||
return (*pCallback)(hwnd) ? TRUE : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(details::always_false<TCallback>::value,
|
||||
"Callback must return void, bool, or HRESULT");
|
||||
}
|
||||
#else
|
||||
return (*pCallback)(hwnd);
|
||||
#endif
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pCallbackData->exception = std::current_exception();
|
||||
return FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_child_window(_In_ HWND hwndParent, TCallback&& callback)
|
||||
{
|
||||
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumChildWindows(hwndParent, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindows(boundEnumChildWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
template <typename TEnumApi, typename TCallback> void DoEnumWindows(TEnumApi &&enumApi, TCallback &&callback)
|
||||
{
|
||||
EnumWindowsCallbackData<TCallback> callbackData = {nullptr, &callback};
|
||||
enumApi(EnumWindowsCallback<TCallback>, reinterpret_cast<LPARAM>(&callbackData));
|
||||
if (callbackData.exception)
|
||||
{
|
||||
std::rethrow_exception(callbackData.exception);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace details
|
||||
|
||||
template <typename TCallback> void for_each_window_nothrow(TCallback &&callback) noexcept
|
||||
{
|
||||
details::DoEnumWindowsNoThrow(&EnumWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_thread_window_nothrow(_In_ DWORD threadId, TCallback &&callback) noexcept
|
||||
{
|
||||
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumThreadWindows(threadId, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindowsNoThrow(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback>
|
||||
void for_each_child_window_nothrow(_In_ HWND hwndParent, TCallback &&callback) noexcept
|
||||
{
|
||||
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumChildWindows(hwndParent, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindowsNoThrow(boundEnumChildWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template <typename TCallback> void for_each_window(TCallback &&callback)
|
||||
{
|
||||
details::DoEnumWindows(&EnumWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback> void for_each_thread_window(_In_ DWORD threadId, TCallback &&callback)
|
||||
{
|
||||
auto boundEnumThreadWindows = [threadId](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumThreadWindows(threadId, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindows(boundEnumThreadWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
|
||||
template <typename TCallback> void for_each_child_window(_In_ HWND hwndParent, TCallback &&callback)
|
||||
{
|
||||
auto boundEnumChildWindows = [hwndParent](WNDENUMPROC enumproc, LPARAM lParam) noexcept -> BOOL {
|
||||
return EnumChildWindows(hwndParent, enumproc, lParam);
|
||||
};
|
||||
details::DoEnumWindows(boundEnumChildWindows, wistd::forward<TCallback>(callback));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace wil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <class _T1, class _T2 = _T1>
|
||||
struct __less
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1& __x, const _T1& __y) const
|
||||
template <class _T1, class _T2 = _T1> 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 <class _T1> struct __less<_T1, _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1 &__x, const _T1 &__y) const
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _T1> struct __less<const _T1, _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1 &__x, const _T1 &__y) const
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _T1> struct __less<_T1, const _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1 &__x, const _T1 &__y) const
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
|
||||
// These are added to wistd to enable use of min/max without having to use the windows.h min/max
|
||||
// macros that some clients might not have access to. Note: the STL versions of these have debug
|
||||
// checking for the less than operator and support for iterators that these implementations lack.
|
||||
// Use the STL versions when you require use of those features.
|
||||
|
||||
// min
|
||||
|
||||
template <class _Tp, class _Compare>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp &(min)(const _Tp &__a,
|
||||
const _Tp &__b,
|
||||
_Compare __comp)
|
||||
{
|
||||
return __comp(__b, __a) ? __b : __a;
|
||||
}
|
||||
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1& __x, const _T2& __y) const
|
||||
template <class _Tp>
|
||||
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 <class _Tp, class _Compare>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp &(max)(const _Tp &__a,
|
||||
const _Tp &__b,
|
||||
_Compare __comp)
|
||||
{
|
||||
return __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 <class _Tp>
|
||||
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 <class _T1>
|
||||
struct __less<_T1, _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1& __x, const _T1& __y) const
|
||||
template <class _Arg, class _Result> struct __WI_LIBCPP_TEMPLATE_VIS unary_function
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
using argument_type = _Arg;
|
||||
using result_type = _Result;
|
||||
};
|
||||
|
||||
template <class _T1>
|
||||
struct __less<const _T1, _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1& __x, const _T1& __y) const
|
||||
template <class _Arg1, class _Arg2, class _Result> struct __WI_LIBCPP_TEMPLATE_VIS binary_function
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
|
||||
template <class _T1>
|
||||
struct __less<_T1, const _T1>
|
||||
{
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 bool operator()(
|
||||
const _T1& __x, const _T1& __y) const
|
||||
{
|
||||
return __x < __y;
|
||||
}
|
||||
};
|
||||
|
||||
// These are added to wistd to enable use of min/max without having to use the windows.h min/max
|
||||
// macros that some clients might not have access to. Note: the STL versions of these have debug
|
||||
// checking for the less than operator and support for iterators that these implementations lack.
|
||||
// Use the STL versions when you require use of those features.
|
||||
|
||||
// min
|
||||
|
||||
template <class _Tp, class _Compare>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(min)(const _Tp& __a, const _Tp& __b, _Compare __comp)
|
||||
{
|
||||
return __comp(__b, __a) ? __b : __a;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(min)(const _Tp& __a, const _Tp& __b)
|
||||
{
|
||||
return (min)(__a, __b, __less<_Tp>());
|
||||
}
|
||||
|
||||
// max
|
||||
|
||||
template <class _Tp, class _Compare>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(max)(const _Tp& __a, const _Tp& __b, _Compare __comp)
|
||||
{
|
||||
return __comp(__a, __b) ? __b : __a;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&(max)(const _Tp& __a, const _Tp& __b)
|
||||
{
|
||||
return (max)(__a, __b, __less<_Tp>());
|
||||
}
|
||||
|
||||
template <class _Arg, class _Result>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS unary_function
|
||||
{
|
||||
using argument_type = _Arg;
|
||||
using result_type = _Result;
|
||||
};
|
||||
|
||||
template <class _Arg1, class _Arg2, class _Result>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS binary_function
|
||||
{
|
||||
using first_argument_type = _Arg1;
|
||||
using second_argument_type = _Arg2;
|
||||
using result_type = _Result;
|
||||
};
|
||||
using first_argument_type = _Arg1;
|
||||
using second_argument_type = _Arg2;
|
||||
using result_type = _Result;
|
||||
};
|
||||
} // namespace wistd
|
||||
/// @endcond
|
||||
|
||||
|
||||
@@ -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 <class _Ret>
|
||||
struct __invoke_void_return_wrapper
|
||||
{
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
template <class... _Args>
|
||||
static _Ret __call(_Args&&... __args)
|
||||
template <class _Ret> struct __invoke_void_return_wrapper
|
||||
{
|
||||
return __invoke(wistd::forward<_Args>(__args)...);
|
||||
}
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
template <class... _Args> static _Ret __call(_Args &&...__args)
|
||||
{
|
||||
return __invoke(wistd::forward<_Args>(__args)...);
|
||||
}
|
||||
#else
|
||||
template <class _Fn>
|
||||
static _Ret __call(_Fn __f)
|
||||
{
|
||||
return __invoke(__f);
|
||||
}
|
||||
template <class _Fn> static _Ret __call(_Fn __f)
|
||||
{
|
||||
return __invoke(__f);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0>
|
||||
static _Ret __call(_Fn __f, _A0& __a0)
|
||||
{
|
||||
return __invoke(__f, __a0);
|
||||
}
|
||||
template <class _Fn, class _A0> static _Ret __call(_Fn __f, _A0 &__a0)
|
||||
{
|
||||
return __invoke(__f, __a0);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0, class _A1>
|
||||
static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1)
|
||||
{
|
||||
return __invoke(__f, __a0, __a1);
|
||||
}
|
||||
template <class _Fn, class _A0, class _A1> static _Ret __call(_Fn __f, _A0 &__a0, _A1 &__a1)
|
||||
{
|
||||
return __invoke(__f, __a0, __a1);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0, class _A1, class _A2>
|
||||
static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2)
|
||||
{
|
||||
return __invoke(__f, __a0, __a1, __a2);
|
||||
}
|
||||
template <class _Fn, class _A0, class _A1, class _A2>
|
||||
static _Ret __call(_Fn __f, _A0 &__a0, _A1 &__a1, _A2 &__a2)
|
||||
{
|
||||
return __invoke(__f, __a0, __a1, __a2);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct __invoke_void_return_wrapper<void>
|
||||
{
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
template <class... _Args>
|
||||
static void __call(_Args&&... __args)
|
||||
template <> struct __invoke_void_return_wrapper<void>
|
||||
{
|
||||
(void)__invoke(wistd::forward<_Args>(__args)...);
|
||||
}
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
template <class... _Args> static void __call(_Args &&...__args)
|
||||
{
|
||||
(void)__invoke(wistd::forward<_Args>(__args)...);
|
||||
}
|
||||
#else
|
||||
template <class _Fn>
|
||||
static void __call(_Fn __f)
|
||||
{
|
||||
__invoke(__f);
|
||||
}
|
||||
template <class _Fn> static void __call(_Fn __f)
|
||||
{
|
||||
__invoke(__f);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0>
|
||||
static void __call(_Fn __f, _A0& __a0)
|
||||
{
|
||||
__invoke(__f, __a0);
|
||||
}
|
||||
template <class _Fn, class _A0> static void __call(_Fn __f, _A0 &__a0)
|
||||
{
|
||||
__invoke(__f, __a0);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0, class _A1>
|
||||
static void __call(_Fn __f, _A0& __a0, _A1& __a1)
|
||||
{
|
||||
__invoke(__f, __a0, __a1);
|
||||
}
|
||||
template <class _Fn, class _A0, class _A1> static void __call(_Fn __f, _A0 &__a0, _A1 &__a1)
|
||||
{
|
||||
__invoke(__f, __a0, __a1);
|
||||
}
|
||||
|
||||
template <class _Fn, class _A0, class _A1, class _A2>
|
||||
static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2)
|
||||
{
|
||||
__invoke(__f, __a0, __a1, __a2);
|
||||
}
|
||||
template <class _Fn, class _A0, class _A1, class _A2>
|
||||
static void __call(_Fn __f, _A0 &__a0, _A1 &__a1, _A2 &__a2)
|
||||
{
|
||||
__invoke(__f, __a0, __a1, __a2);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// FUNCTION
|
||||
//==============================================================================
|
||||
|
||||
// bad_function_call
|
||||
|
||||
__WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY void __throw_bad_function_call()
|
||||
{
|
||||
__fastfail(7); // FAST_FAIL_FATAL_APP_EXIT
|
||||
}
|
||||
|
||||
template <class _Fp>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS function; // undefined
|
||||
|
||||
namespace __function
|
||||
{
|
||||
|
||||
template <class _Rp>
|
||||
struct __maybe_derive_from_unary_function
|
||||
{
|
||||
};
|
||||
|
||||
template <class _Rp, class _A1>
|
||||
struct __maybe_derive_from_unary_function<_Rp(_A1)> : public unary_function<_A1, _Rp>
|
||||
{
|
||||
};
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// FUNCTION
|
||||
//==============================================================================
|
||||
|
||||
template <class _Rp>
|
||||
struct __maybe_derive_from_binary_function
|
||||
{
|
||||
};
|
||||
// bad_function_call
|
||||
|
||||
template <class _Rp, class _A1, class _A2>
|
||||
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 <class _Fp>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp const&)
|
||||
{
|
||||
return true;
|
||||
__fastfail(7); // FAST_FAIL_FATAL_APP_EXIT
|
||||
}
|
||||
|
||||
template <class _Fp>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp* __ptr)
|
||||
{
|
||||
return __ptr;
|
||||
}
|
||||
template <class _Fp> class __WI_LIBCPP_TEMPLATE_VIS function; // undefined
|
||||
|
||||
template <class _Ret, class _Class>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Ret _Class::* __ptr)
|
||||
namespace __function
|
||||
{
|
||||
return __ptr;
|
||||
}
|
||||
|
||||
template <class _Fp>
|
||||
__WI_LIBCPP_INLINE_VISIBILITY bool __not_null(function<_Fp> const& __f)
|
||||
{
|
||||
return !!__f;
|
||||
}
|
||||
template <class _Rp> struct __maybe_derive_from_unary_function
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace __function
|
||||
template <class _Rp, class _A1>
|
||||
struct __maybe_derive_from_unary_function<_Rp(_A1)> : public unary_function<_A1, _Rp>
|
||||
{
|
||||
};
|
||||
|
||||
template <class _Rp> struct __maybe_derive_from_binary_function
|
||||
{
|
||||
};
|
||||
|
||||
template <class _Rp, class _A1, class _A2>
|
||||
struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public binary_function<_A1, _A2, _Rp>
|
||||
{
|
||||
};
|
||||
|
||||
template <class _Fp> __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp const &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class _Fp> __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Fp *__ptr)
|
||||
{
|
||||
return __ptr;
|
||||
}
|
||||
|
||||
template <class _Ret, class _Class> __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(_Ret _Class::*__ptr)
|
||||
{
|
||||
return __ptr;
|
||||
}
|
||||
|
||||
template <class _Fp> __WI_LIBCPP_INLINE_VISIBILITY bool __not_null(function<_Fp> const &__f)
|
||||
{
|
||||
return !!__f;
|
||||
}
|
||||
|
||||
} // namespace __function
|
||||
|
||||
#ifndef __WI_LIBCPP_CXX03_LANG
|
||||
|
||||
namespace __function
|
||||
{
|
||||
namespace __function
|
||||
{
|
||||
|
||||
template <class _Fp>
|
||||
class __base;
|
||||
template <class _Fp> class __base;
|
||||
|
||||
template <class _Rp, class... _ArgTypes> class __base<_Rp(_ArgTypes...)>
|
||||
{
|
||||
__base(const __base &);
|
||||
__base &operator=(const __base &);
|
||||
|
||||
public:
|
||||
__WI_LIBCPP_INLINE_VISIBILITY __base()
|
||||
{
|
||||
}
|
||||
__WI_LIBCPP_INLINE_VISIBILITY virtual ~__base()
|
||||
{
|
||||
}
|
||||
virtual void __clone(__base *) const = 0;
|
||||
virtual void __move(__base *) = 0;
|
||||
virtual void destroy() WI_NOEXCEPT = 0;
|
||||
virtual _Rp operator()(_ArgTypes &&...) = 0;
|
||||
};
|
||||
|
||||
template <class _FD, class _FB> class __func;
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)>
|
||||
{
|
||||
_Fp __f_;
|
||||
|
||||
public:
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
explicit __func(_Fp &&__f) : __f_(wistd::move(__f))
|
||||
{
|
||||
}
|
||||
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
explicit __func(const _Fp &__f) : __f_(__f)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void __clone(__base<_Rp(_ArgTypes...)> *) const;
|
||||
virtual void __move(__base<_Rp(_ArgTypes...)> *);
|
||||
virtual void destroy() WI_NOEXCEPT;
|
||||
virtual _Rp operator()(_ArgTypes &&...__arg);
|
||||
};
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
void __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)> *__p) const
|
||||
{
|
||||
::new (__p) __func(__f_);
|
||||
}
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
void __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)> *__p)
|
||||
{
|
||||
::new (__p) __func(wistd::move(__f_));
|
||||
}
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes> void __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT
|
||||
{
|
||||
__f_.~_Fp();
|
||||
}
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
_Rp __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes &&...__arg)
|
||||
{
|
||||
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
|
||||
return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...);
|
||||
}
|
||||
|
||||
// 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects
|
||||
// that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12
|
||||
// pointers (__base vtable takes an additional one).
|
||||
constexpr const size_t __buffer_size = 13 * sizeof(void *);
|
||||
|
||||
} // namespace __function
|
||||
|
||||
// NOTE: The extra 'alignas' here is to work around the x86 compiler bug mentioned in
|
||||
// https://github.com/microsoft/STL/issues/1533 to force alignment on the stack
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS __WI_ALIGNAS(typename aligned_storage<__function::__buffer_size>::type)
|
||||
function<_Rp(_ArgTypes...)> : public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>,
|
||||
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)>
|
||||
{
|
||||
using __base = __function::__base<_Rp(_ArgTypes...)>;
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
typename aligned_storage<__function::__buffer_size>::type __buf_;
|
||||
__base *__f_;
|
||||
|
||||
__WI_LIBCPP_NO_CFI static __base *__as_base(void *p)
|
||||
{
|
||||
return static_cast<__base *>(p);
|
||||
}
|
||||
|
||||
template <class _Fp, bool> struct __callable_imp
|
||||
{
|
||||
static const bool value = is_same<void, _Rp>::value ||
|
||||
is_convertible<typename __invoke_of<_Fp &, _ArgTypes...>::type, _Rp>::value;
|
||||
};
|
||||
|
||||
template <class _Fp> struct __callable_imp<_Fp, false>
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class _Fp> struct __callable
|
||||
{
|
||||
static const bool value =
|
||||
__callable_imp<_Fp, __lazy_and<integral_constant<bool, !is_same<__uncvref_t<_Fp>, function>::value>,
|
||||
__invokable<_Fp &, _ArgTypes...>>::value>::value;
|
||||
};
|
||||
|
||||
template <class _Fp> using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type;
|
||||
|
||||
public:
|
||||
using result_type = _Rp;
|
||||
|
||||
// construct/copy/destroy:
|
||||
__WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function() WI_NOEXCEPT : __f_(0)
|
||||
{
|
||||
}
|
||||
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
function(nullptr_t) WI_NOEXCEPT : __f_(0)
|
||||
{
|
||||
}
|
||||
function(const function &);
|
||||
function(function &&);
|
||||
template <class _Fp, class = _EnableIfCallable<_Fp>> function(_Fp);
|
||||
|
||||
function &operator=(const function &);
|
||||
function &operator=(function &&);
|
||||
function &operator=(nullptr_t) WI_NOEXCEPT;
|
||||
template <class _Fp, class = _EnableIfCallable<_Fp>> function &operator=(_Fp &&);
|
||||
|
||||
~function();
|
||||
|
||||
// function modifiers:
|
||||
void swap(function &);
|
||||
|
||||
// function capacity:
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT
|
||||
operator bool() const WI_NOEXCEPT
|
||||
{
|
||||
return __f_;
|
||||
}
|
||||
|
||||
// deleted overloads close possible hole in the type system
|
||||
template <class _R2, class... _ArgTypes2> bool operator==(const function<_R2(_ArgTypes2...)> &) const = delete;
|
||||
template <class _R2, class... _ArgTypes2> bool operator!=(const function<_R2(_ArgTypes2...)> &) const = delete;
|
||||
|
||||
public:
|
||||
// function invocation:
|
||||
_Rp operator()(_ArgTypes...) const;
|
||||
|
||||
// NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than
|
||||
// 'std' so all functions requiring RTTI have been removed
|
||||
};
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
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 _FD, class _FB>
|
||||
class __func;
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)>
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
__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 <class _Rp, class... _ArgTypes>
|
||||
template <class _Fp, class>
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(nullptr)
|
||||
{
|
||||
if (__function::__not_null(__f))
|
||||
{
|
||||
typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). "
|
||||
"Refactor to reduce size of the capture.");
|
||||
__f_ = ::new (static_cast<void *>(&__buf_)) _FF(wistd::move(__f));
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(const function &__f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__f.__f_)
|
||||
{
|
||||
__f_ = __as_base(&__buf_);
|
||||
__f.__f_->__clone(__f_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(function &&__f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__f.__f_)
|
||||
{
|
||||
__f_ = __as_base(&__buf_);
|
||||
__f.__f_->__move(__f_);
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT
|
||||
{
|
||||
__base *__t = __f_;
|
||||
__f_ = 0;
|
||||
if (__t)
|
||||
__t->destroy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
template <class _Fp, class>
|
||||
function<_Rp(_ArgTypes...)> &function<_Rp(_ArgTypes...)>::operator=(_Fp &&__f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__function::__not_null(__f))
|
||||
{
|
||||
typedef __function::__func<typename decay<_Fp>::type, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). "
|
||||
"Refactor to reduce size of the capture.");
|
||||
__f_ = ::new (static_cast<void *>(&__buf_)) _FF(wistd::move(__f));
|
||||
}
|
||||
|
||||
__WI_LIBCPP_INLINE_VISIBILITY
|
||||
explicit __func(const _Fp& __f) : __f_(__f)
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes> function<_Rp(_ArgTypes...)>::~function()
|
||||
{
|
||||
if (__f_)
|
||||
__f_->destroy();
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes> void function<_Rp(_ArgTypes...)>::swap(function &__f)
|
||||
{
|
||||
if (wistd::addressof(__f) == this)
|
||||
return;
|
||||
if (__f_ && __f.__f_)
|
||||
{
|
||||
typename aligned_storage<sizeof(__buf_)>::type __tempbuf;
|
||||
__base *__t = __as_base(&__tempbuf);
|
||||
__f_->__move(__t);
|
||||
__f_->destroy();
|
||||
__f_ = 0;
|
||||
__f.__f_->__move(__as_base(&__buf_));
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
__f_ = __as_base(&__buf_);
|
||||
__t->__move(__as_base(&__f.__buf_));
|
||||
__t->destroy();
|
||||
__f.__f_ = __as_base(&__f.__buf_);
|
||||
}
|
||||
else if (__f_)
|
||||
{
|
||||
__f_->__move(__as_base(&__f.__buf_));
|
||||
__f_->destroy();
|
||||
__f_ = 0;
|
||||
__f.__f_ = __as_base(&__f.__buf_);
|
||||
}
|
||||
else if (__f.__f_)
|
||||
{
|
||||
__f.__f_->__move(__as_base(&__buf_));
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
__f_ = __as_base(&__buf_);
|
||||
}
|
||||
|
||||
virtual void __clone(__base<_Rp(_ArgTypes...)>*) const;
|
||||
virtual void __move(__base<_Rp(_ArgTypes...)>*);
|
||||
virtual void destroy() WI_NOEXCEPT;
|
||||
virtual _Rp operator()(_ArgTypes&&... __arg);
|
||||
};
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
void __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const
|
||||
{
|
||||
::new (__p) __func(__f_);
|
||||
}
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
void __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p)
|
||||
template <class _Rp, class... _ArgTypes> _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 <class _Fp, class _Rp, class... _ArgTypes>
|
||||
void __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const function<_Rp(_ArgTypes...)> &__f, nullptr_t) WI_NOEXCEPT
|
||||
{
|
||||
__f_.~_Fp();
|
||||
return !__f;
|
||||
}
|
||||
|
||||
template <class _Fp, class _Rp, class... _ArgTypes>
|
||||
_Rp __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg)
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
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 _Rp, class... _ArgTypes>
|
||||
class __WI_LIBCPP_TEMPLATE_VIS __WI_ALIGNAS(typename aligned_storage<__function::__buffer_size>::type) function<_Rp(_ArgTypes...)>
|
||||
: public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>,
|
||||
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)>
|
||||
{
|
||||
using __base = __function::__base<_Rp(_ArgTypes...)>;
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS
|
||||
typename aligned_storage<__function::__buffer_size>::type __buf_;
|
||||
__base* __f_;
|
||||
|
||||
__WI_LIBCPP_NO_CFI static __base* __as_base(void* p)
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
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 <class _Fp, bool>
|
||||
struct __callable_imp
|
||||
{
|
||||
static const bool value = is_same<void, _Rp>::value || is_convertible<typename __invoke_of<_Fp&, _ArgTypes...>::type, _Rp>::value;
|
||||
};
|
||||
|
||||
template <class _Fp>
|
||||
struct __callable_imp<_Fp, false>
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class _Fp>
|
||||
struct __callable
|
||||
{
|
||||
static const bool value =
|
||||
__callable_imp<_Fp, __lazy_and<integral_constant<bool, !is_same<__uncvref_t<_Fp>, function>::value>, __invokable<_Fp&, _ArgTypes...>>::value>::value;
|
||||
};
|
||||
|
||||
template <class _Fp>
|
||||
using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type;
|
||||
|
||||
public:
|
||||
using result_type = _Rp;
|
||||
|
||||
// construct/copy/destroy:
|
||||
__WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function() WI_NOEXCEPT : __f_(0)
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
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 <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY void swap(function<_Rp(_ArgTypes...)> &__x, function<_Rp(_ArgTypes...)> &__y)
|
||||
{
|
||||
}
|
||||
function(const function&);
|
||||
function(function&&);
|
||||
template <class _Fp, class = _EnableIfCallable<_Fp>>
|
||||
function(_Fp);
|
||||
|
||||
function& operator=(const function&);
|
||||
function& operator=(function&&);
|
||||
function& operator=(nullptr_t) WI_NOEXCEPT;
|
||||
template <class _Fp, class = _EnableIfCallable<_Fp>>
|
||||
function& operator=(_Fp&&);
|
||||
|
||||
~function();
|
||||
|
||||
// function modifiers:
|
||||
void swap(function&);
|
||||
|
||||
// function capacity:
|
||||
__WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT
|
||||
{
|
||||
return __f_;
|
||||
return __x.swap(__y);
|
||||
}
|
||||
|
||||
// deleted overloads close possible hole in the type system
|
||||
template <class _R2, class... _ArgTypes2>
|
||||
bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete;
|
||||
template <class _R2, class... _ArgTypes2>
|
||||
bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete;
|
||||
|
||||
public:
|
||||
// function invocation:
|
||||
_Rp operator()(_ArgTypes...) const;
|
||||
|
||||
// NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than
|
||||
// 'std' so all functions requiring RTTI have been removed
|
||||
};
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(const function& __f)
|
||||
{
|
||||
if (__f.__f_ == nullptr)
|
||||
__f_ = 0;
|
||||
else
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
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 <class _Rp, class... _ArgTypes>
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS function<_Rp(_ArgTypes...)>::function(function&& __f)
|
||||
{
|
||||
if (__f.__f_ == nullptr)
|
||||
__f_ = 0;
|
||||
else
|
||||
{
|
||||
__f_ = __as_base(&__buf_);
|
||||
__f.__f_->__move(__f_);
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
template <class _Fp, class>
|
||||
__WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(nullptr)
|
||||
{
|
||||
if (__function::__not_null(__f))
|
||||
{
|
||||
typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(
|
||||
sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
|
||||
__f_ = ::new (static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(const function& __f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__f.__f_)
|
||||
{
|
||||
__f_ = __as_base(&__buf_);
|
||||
__f.__f_->__clone(__f_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(function&& __f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__f.__f_)
|
||||
{
|
||||
__f_ = __as_base(&__buf_);
|
||||
__f.__f_->__move(__f_);
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT
|
||||
{
|
||||
__base* __t = __f_;
|
||||
__f_ = 0;
|
||||
if (__t)
|
||||
__t->destroy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
template <class _Fp, class>
|
||||
function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f)
|
||||
{
|
||||
*this = nullptr;
|
||||
if (__function::__not_null(__f))
|
||||
{
|
||||
typedef __function::__func<typename decay<_Fp>::type, _Rp(_ArgTypes...)> _FF;
|
||||
static_assert(
|
||||
sizeof(_FF) <= sizeof(__buf_),
|
||||
"The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture.");
|
||||
__f_ = ::new (static_cast<void*>(&__buf_)) _FF(wistd::move(__f));
|
||||
return __x.swap(__y);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
function<_Rp(_ArgTypes...)>::~function()
|
||||
{
|
||||
if (__f_)
|
||||
__f_->destroy();
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
void function<_Rp(_ArgTypes...)>::swap(function& __f)
|
||||
{
|
||||
if (wistd::addressof(__f) == this)
|
||||
return;
|
||||
if (__f_ && __f.__f_)
|
||||
// std::invoke
|
||||
template <class _Fn, class... _Args>
|
||||
typename __invoke_of<_Fn, _Args...>::type invoke(_Fn &&__f, _Args &&...__args)
|
||||
__WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value))
|
||||
{
|
||||
typename aligned_storage<sizeof(__buf_)>::type __tempbuf;
|
||||
__base* __t = __as_base(&__tempbuf);
|
||||
__f_->__move(__t);
|
||||
__f_->destroy();
|
||||
__f_ = 0;
|
||||
__f.__f_->__move(__as_base(&__buf_));
|
||||
__f.__f_->destroy();
|
||||
__f.__f_ = 0;
|
||||
__f_ = __as_base(&__buf_);
|
||||
__t->__move(__as_base(&__f.__buf_));
|
||||
__t->destroy();
|
||||
__f.__f_ = __as_base(&__f.__buf_);
|
||||
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 <class _Rp, class... _ArgTypes>
|
||||
_Rp function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const
|
||||
{
|
||||
if (__f_ == nullptr)
|
||||
__throw_bad_function_call();
|
||||
return (*__f_)(wistd::forward<_ArgTypes>(__arg)...);
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT
|
||||
{
|
||||
return !__f;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT
|
||||
{
|
||||
return !__f;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT
|
||||
{
|
||||
return (bool)__f;
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY bool operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT
|
||||
{
|
||||
return (bool)__f;
|
||||
}
|
||||
|
||||
// Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY void swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y)
|
||||
{
|
||||
return __x.swap(__y);
|
||||
}
|
||||
|
||||
template <class _Rp, class... _ArgTypes>
|
||||
inline __WI_LIBCPP_INLINE_VISIBILITY void swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y)
|
||||
{
|
||||
return __x.swap(__y);
|
||||
}
|
||||
|
||||
// std::invoke
|
||||
template <class _Fn, class... _Args>
|
||||
typename __invoke_of<_Fn, _Args...>::type invoke(_Fn&& __f, _Args&&... __args)
|
||||
__WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value))
|
||||
{
|
||||
return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
#else // __WI_LIBCPP_CXX03_LANG
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,10 @@
|
||||
#ifndef __WIL_WRL_INCLUDED
|
||||
#define __WIL_WRL_INCLUDED
|
||||
|
||||
#include <wrl.h>
|
||||
#include "common.h" // wistd type_traits helpers
|
||||
#include "result.h"
|
||||
#include "common.h" // wistd type_traits helpers
|
||||
#include <libloaderapi.h> // GetModuleHandleW
|
||||
#include <wrl.h>
|
||||
|
||||
/// @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<SomeClass>(L"input", true);
|
||||
@endcode
|
||||
*/
|
||||
template <typename T, typename... TArgs>
|
||||
Microsoft::WRL::ComPtr<T> MakeAndInitializeOrThrow(TArgs&&... args)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<T> obj;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<T>(&obj, Microsoft::WRL::Details::Forward<TArgs>(args)...));
|
||||
return obj;
|
||||
}
|
||||
/** Used to construct a RuntimeClass based object that uses 2 phase construction.
|
||||
Construct a RuntimeClass based object that uses 2 phase construction (by implementing
|
||||
RuntimeClassInitialize() and returning error codes for failures.
|
||||
@code
|
||||
// SomeClass uses 2 phase initialization by implementing RuntimeClassInitialize()
|
||||
auto someClass = MakeAndInitializeOrThrow<SomeClass>(L"input", true);
|
||||
@endcode
|
||||
*/
|
||||
template <typename T, typename... TArgs> Microsoft::WRL::ComPtr<T> MakeAndInitializeOrThrow(TArgs &&...args)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<T> obj;
|
||||
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<T>(&obj, Microsoft::WRL::Details::Forward<TArgs>(args)...));
|
||||
return obj;
|
||||
}
|
||||
|
||||
/** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does
|
||||
not require 2 phase construction).
|
||||
@code
|
||||
// SomeClass uses exceptions for error handling in its constructor.
|
||||
auto someClass = MakeOrThrow<SomeClass>(L"input", true);
|
||||
@endcode
|
||||
*/
|
||||
template <typename T, typename... TArgs>
|
||||
Microsoft::WRL::ComPtr<T> MakeOrThrow(TArgs&&... args)
|
||||
{
|
||||
// This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use.
|
||||
// Unfortunately this produces false positives as all RuntimeClass derived classes have
|
||||
// a RuntimeClassInitialize() method from their base class.
|
||||
// static_assert(!std::is_member_function_pointer<decltype(&T::RuntimeClassInitialize)>::value,
|
||||
// "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead");
|
||||
auto obj = Microsoft::WRL::Make<T>(Microsoft::WRL::Details::Forward<TArgs>(args)...);
|
||||
THROW_IF_NULL_ALLOC(obj.Get());
|
||||
return obj;
|
||||
}
|
||||
/** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does
|
||||
not require 2 phase construction).
|
||||
@code
|
||||
// SomeClass uses exceptions for error handling in its constructor.
|
||||
auto someClass = MakeOrThrow<SomeClass>(L"input", true);
|
||||
@endcode
|
||||
*/
|
||||
template <typename T, typename... TArgs> Microsoft::WRL::ComPtr<T> MakeOrThrow(TArgs &&...args)
|
||||
{
|
||||
// This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use.
|
||||
// Unfortunately this produces false positives as all RuntimeClass derived classes have
|
||||
// a RuntimeClassInitialize() method from their base class.
|
||||
// static_assert(!std::is_member_function_pointer<decltype(&T::RuntimeClassInitialize)>::value,
|
||||
// "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead");
|
||||
auto obj = Microsoft::WRL::Make<T>(Microsoft::WRL::Details::Forward<TArgs>(args)...);
|
||||
THROW_IF_NULL_ALLOC(obj.Get());
|
||||
return obj;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
/** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with
|
||||
MakeAgileCallback<>. Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() from wil/result.h
|
||||
to test the result. */
|
||||
template <typename TDelegateInterface, typename... Args>
|
||||
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT
|
||||
{
|
||||
using namespace Microsoft::WRL;
|
||||
return Callback<Implements<RuntimeClassFlags<ClassicCom>, TDelegateInterface, FtmBase>>(wistd::forward<Args>(args)...);
|
||||
}
|
||||
/** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with
|
||||
MakeAgileCallback<>. Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() from
|
||||
wil/result.h to test the result. */
|
||||
template <typename TDelegateInterface, typename... Args>
|
||||
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallbackNoThrow(Args &&...args) WI_NOEXCEPT
|
||||
{
|
||||
using namespace Microsoft::WRL;
|
||||
return Callback<Implements<RuntimeClassFlags<ClassicCom>, TDelegateInterface, FtmBase>>(
|
||||
wistd::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
template <typename TDelegateInterface, typename... Args>
|
||||
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallback(Args&&... args)
|
||||
{
|
||||
auto result = MakeAgileCallbackNoThrow<TDelegateInterface, Args...>(wistd::forward<Args>(args)...);
|
||||
THROW_IF_NULL_ALLOC(result);
|
||||
return result;
|
||||
}
|
||||
template <typename TDelegateInterface, typename... Args>
|
||||
::Microsoft::WRL::ComPtr<TDelegateInterface> MakeAgileCallback(Args &&...args)
|
||||
{
|
||||
auto result = MakeAgileCallbackNoThrow<TDelegateInterface, Args...>(wistd::forward<Args>(args)...);
|
||||
THROW_IF_NULL_ALLOC(result);
|
||||
return result;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
/** Holds a reference to the host WRL module to prevent it from being unloaded.
|
||||
Normally, the reference is held implicitly because you are a member function
|
||||
of a DLL-hosted COM object, or because you retain a strong reference
|
||||
to some DLL-hosted COM object, but if those do not apply to you, then you
|
||||
will need to hold a reference explicitly. For examples (and for the C++/WinRT
|
||||
equivalent), see winrt_module_reference.
|
||||
*/
|
||||
struct [[nodiscard]] wrl_module_reference
|
||||
{
|
||||
wrl_module_reference()
|
||||
/** 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<HMODULE>(&__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<HMODULE>(&__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
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include <objbase.h>
|
||||
#include <cstdint>
|
||||
#include <compare>
|
||||
#include "wil/result_macros.h"
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
#include <objbase.h>
|
||||
#ifdef _CPPRTTI
|
||||
#include <rttidata.h>
|
||||
#include <typeinfo>
|
||||
@@ -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<typename T>
|
||||
using reg_return_t = std::conditional_t<(std::is_class_v<T> || std::is_union_v<T>) && (sizeof(T) <= sizeof(std::uintptr_t)), std::uintptr_t, T>;
|
||||
template <typename T>
|
||||
using reg_return_t =
|
||||
std::conditional_t<(std::is_class_v<T> || std::is_union_v<T>) && (sizeof(T) <= sizeof(std::uintptr_t)),
|
||||
std::uintptr_t, T>;
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE reg_return_t<T> to_reg_return(T value)
|
||||
template <typename T> FORCEINLINE reg_return_t<T> to_reg_return(T value)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, reg_return_t<T>>)
|
||||
return value;
|
||||
@@ -48,37 +49,40 @@ namespace xcom
|
||||
{
|
||||
namespace impl
|
||||
{
|
||||
template<typename T>
|
||||
inline constexpr GUID guid_v = __uuidof(T);
|
||||
template <typename T> inline constexpr GUID guid_v = __uuidof(T);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr GUID guid_of() { return impl::guid_v<T>; }
|
||||
template <typename T> inline constexpr GUID guid_of()
|
||||
{
|
||||
return impl::guid_v<T>;
|
||||
}
|
||||
|
||||
template<template<abi_t> typename T>
|
||||
inline constexpr GUID guid_of() { return guid_of<T<abi_t{}>>(); }
|
||||
template <template <abi_t> typename T> inline constexpr GUID guid_of()
|
||||
{
|
||||
return guid_of<T<abi_t{}>>();
|
||||
}
|
||||
|
||||
inline void StubHandler(char const *name, void *object)
|
||||
{
|
||||
#ifdef _CPPRTTI
|
||||
#ifdef _CPPRTTI
|
||||
char const *type = object ? ((type_info const *)__RTtypeid(object))->name() : "STUB";
|
||||
#else
|
||||
#else
|
||||
char const *type = "STUB";
|
||||
#endif
|
||||
#endif
|
||||
MessageBoxA(nullptr, name, type, MB_ICONERROR);
|
||||
#ifdef _DEBUG
|
||||
#ifdef _DEBUG
|
||||
DebugBreak();
|
||||
#endif
|
||||
#endif
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
inline void TodoHandler(char const *name, void *object)
|
||||
{
|
||||
#ifdef _CPPRTTI
|
||||
#ifdef _CPPRTTI
|
||||
char const *type = object ? ((type_info const *)__RTtypeid(object))->name() : nullptr;
|
||||
#else
|
||||
#else
|
||||
char const *type = nullptr;
|
||||
#endif
|
||||
#endif
|
||||
OutputDebugStringA("TODO: ");
|
||||
OutputDebugStringA(name);
|
||||
|
||||
@@ -111,12 +115,14 @@ namespace xcom
|
||||
*ppvObject = nullptr;
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
} // namespace xcom
|
||||
|
||||
#ifndef DECLARE_UUIDOF_HELPER
|
||||
#define DECLARE_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) template<> inline constexpr GUID (::xcom::impl::guid_v<type>){a,b,c,{d,e,f,g,h,i,j,k}};
|
||||
#define DECLARE_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) \
|
||||
template <> inline constexpr GUID(::xcom::impl::guid_v<type>){a, b, c, {d, e, f, g, h, i, j, k}};
|
||||
#endif
|
||||
|
||||
#define DECLARE_ABI_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) template<> inline constexpr GUID (::xcom::impl::guid_v<type<abi_t{}>>){a,b,c,{d,e,f,g,h,i,j,k}};
|
||||
#define IMPLEMENT_STUB() ::xcom::StubHandler(__func__, __if_exists(this) { this } __if_not_exists(this) { nullptr })
|
||||
#define IMPLEMENT_TODO() ::xcom::TodoHandler(__func__, __if_exists(this) { this } __if_not_exists(this) { nullptr })
|
||||
#define DECLARE_ABI_UUIDOF_HELPER(type, a, b, c, d, e, f, g, h, i, j, k) \
|
||||
template <> inline constexpr GUID(::xcom::impl::guid_v<type<abi_t{}>>){a, b, c, {d, e, f, g, h, i, j, k}};
|
||||
#define IMPLEMENT_STUB() ::xcom::StubHandler(__func__, __if_exists(this) { this } __if_not_exists(this){nullptr})
|
||||
#define IMPLEMENT_TODO() ::xcom::TodoHandler(__func__, __if_exists(this) { this } __if_not_exists(this){nullptr})
|
||||
|
||||
@@ -3,22 +3,19 @@
|
||||
//
|
||||
// IUnknown
|
||||
//
|
||||
template<abi_t ABI>
|
||||
HRESULT GraphicsUnknown<ABI>::QueryInterface(REFIID riid, void** ppvObject)
|
||||
template <abi_t ABI> HRESULT GraphicsUnknown<ABI>::QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
template<abi_t ABI>
|
||||
ULONG GraphicsUnknown<ABI>::AddRef()
|
||||
template <abi_t ABI> ULONG GraphicsUnknown<ABI>::AddRef()
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return {};
|
||||
}
|
||||
|
||||
template<abi_t ABI>
|
||||
ULONG GraphicsUnknown<ABI>::Release()
|
||||
template <abi_t ABI> ULONG GraphicsUnknown<ABI>::Release()
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return {};
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
DEFINE_GUID(IID_IPrivateData, 0x34DC21A0, 0x5DFC, 0x4C03, 0xB6, 0xA9, 0x8F, 0x75, 0x30, 0x5B, 0x85, 0xE6);
|
||||
DEFINE_GUID(IID_IGraphicsUnknown, 0xACEEEA63, 0xE0A9, 0x4A1C, 0xBB, 0xEC, 0x71, 0xB2, 0xF4, 0x85, 0xF7, 0x58);
|
||||
DEFINE_GUID(IID_ID3D11UserDefinedAnnotationX, 0xB2DAAD8B, 0x03D4, 0x4DBF, 0x95, 0xEB, 0x32, 0xAB, 0x4B, 0x63, 0xD0, 0xAB);
|
||||
DEFINE_GUID(IID_ID3D11UserDefinedAnnotationX, 0xB2DAAD8B, 0x03D4, 0x4DBF, 0x95, 0xEB, 0x32, 0xAB, 0x4B, 0x63, 0xD0,
|
||||
0xAB);
|
||||
DEFINE_GUID(IID_ID3D11PIXPlaybackContextX, 0xC9225B7A, 0x4D50, 0x4EE0, 0x8E, 0x02, 0x28, 0x4D, 0x18, 0xF8, 0x39, 0x5D);
|
||||
DEFINE_GUID(IID_ID3D11PerformanceDeviceX, 0x88671610, 0x712E, 0x4F1E, 0x84, 0xAB, 0x01, 0xB5, 0x94, 0x8B, 0xD3, 0x73);
|
||||
DEFINE_GUID(IID_ID3D11PerformanceContextX, 0x9458FE06, 0xC78D, 0x47F7, 0x96, 0xA0, 0xEC, 0x7B, 0x72, 0x7B, 0xE1, 0xE9);
|
||||
|
||||
@@ -7,16 +7,10 @@ EXTERN_C HRESULT __stdcall EraD3D10CreateBlob()
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT __stdcall EraD3D11CreateDevice(void* pAdapter,
|
||||
D3D_DRIVER_TYPE DriverType,
|
||||
HMODULE Software,
|
||||
UINT Flags,
|
||||
const D3D_FEATURE_LEVEL* pFeatureLevels,
|
||||
UINT FeatureLevels,
|
||||
UINT SDKVersion,
|
||||
void** ppDevice,
|
||||
D3D_FEATURE_LEVEL* pFeatureLevel,
|
||||
void** ppImmediateContext)
|
||||
EXTERN_C HRESULT __stdcall EraD3D11CreateDevice(void *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software,
|
||||
UINT Flags, const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels,
|
||||
UINT SDKVersion, void **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel,
|
||||
void **ppImmediateContext)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
@@ -32,8 +26,8 @@ struct D3D11X_CREATE_DEVICE_PARAMETERS
|
||||
{
|
||||
UINT Version;
|
||||
UINT Flags;
|
||||
void* pOffchipTessellationBuffer;
|
||||
void* pTessellationFactorsBuffer;
|
||||
void *pOffchipTessellationBuffer;
|
||||
void *pTessellationFactorsBuffer;
|
||||
UINT DeferredDeletionThreadAffinityMask;
|
||||
UINT ImmediateContextDeRingSizeBytes;
|
||||
UINT ImmediateContextCeRingSizeBytes;
|
||||
@@ -41,27 +35,23 @@ struct D3D11X_CREATE_DEVICE_PARAMETERS
|
||||
UINT ImmediateContextCeSegmentSizeBytes;
|
||||
};
|
||||
|
||||
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceX(const D3D11X_CREATE_DEVICE_PARAMETERS* pParameters,
|
||||
void** ppDevice,
|
||||
void** ppImmediateContext)
|
||||
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceX(const D3D11X_CREATE_DEVICE_PARAMETERS *pParameters, void **ppDevice,
|
||||
void **ppImmediateContext)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceXAndSwapChain1(
|
||||
const D3D11X_CREATE_DEVICE_PARAMETERS* pParameters,
|
||||
const DXGI_SWAP_CHAIN_DESC1* pSwapChainDesc,
|
||||
void** ppSwapChain,
|
||||
void** ppDevice,
|
||||
void** ppImmediateContext)
|
||||
EXTERN_C HRESULT __stdcall D3D11XCreateDeviceXAndSwapChain1(const D3D11X_CREATE_DEVICE_PARAMETERS *pParameters,
|
||||
const DXGI_SWAP_CHAIN_DESC1 *pSwapChainDesc,
|
||||
void **ppSwapChain, void **ppDevice,
|
||||
void **ppImmediateContext)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT __stdcall D3DAllocateGraphicsMemory(SIZE_T dwSize, UINT64 a2, void* a3, int a4, void** a5)
|
||||
EXTERN_C HRESULT __stdcall D3DAllocateGraphicsMemory(SIZE_T dwSize, UINT64 a2, void *a3, int a4, void **a5)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
@@ -73,13 +63,13 @@ EXTERN_C HRESULT __stdcall D3DConfigureVirtualMemory(UINT64 a1)
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT __stdcall D3DFreeGraphicsMemory(void* pAddress)
|
||||
EXTERN_C HRESULT __stdcall D3DFreeGraphicsMemory(void *pAddress)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT __stdcall D3DMapEsramMemory(UINT Flags, void* pVirtualAddress, UINT NumPages, const UINT* pPageList)
|
||||
EXTERN_C HRESULT __stdcall D3DMapEsramMemory(UINT Flags, void *pVirtualAddress, UINT NumPages, const UINT *pPageList)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
@@ -100,10 +90,10 @@ struct DXGIX_FRAME_STATISTICS
|
||||
UINT64 GPUTimeFlip;
|
||||
UINT64 VSyncCount;
|
||||
float PercentScanned;
|
||||
void* Cookie[2];
|
||||
void *Cookie[2];
|
||||
};
|
||||
|
||||
EXTERN_C HRESULT __stdcall DXGIXGetFrameStatistics(UINT NumberFramesRequested, DXGIX_FRAME_STATISTICS* pFrameStatistics)
|
||||
EXTERN_C HRESULT __stdcall DXGIXGetFrameStatistics(UINT NumberFramesRequested, DXGIX_FRAME_STATISTICS *pFrameStatistics)
|
||||
{
|
||||
pFrameStatistics->QueueLengthAddedToQueue = 0;
|
||||
pFrameStatistics->CPUTimeAddedToQueue = 0;
|
||||
@@ -130,21 +120,18 @@ struct DXGIX_PRESENTARRAY_PARAMETERS
|
||||
POINT DestRectUpperLeft;
|
||||
FLOAT ScaleFactorVert;
|
||||
FLOAT ScaleFactorHorz;
|
||||
void* Cookie;
|
||||
UINT Flags;
|
||||
void *Cookie;
|
||||
UINT Flags;
|
||||
};
|
||||
|
||||
void PresentArray(UINT NumSwapChains, void** SwapChains, UINT SyncInterval)
|
||||
void PresentArray(UINT NumSwapChains, void **SwapChains, UINT SyncInterval)
|
||||
{
|
||||
//TODO
|
||||
// TODO
|
||||
}
|
||||
|
||||
EXTERN_C HRESULT __stdcall DXGIXPresentArray(UINT SyncInterval,
|
||||
UINT PresentImmediateThreshold,
|
||||
UINT Flags,
|
||||
UINT NumSwapChains,
|
||||
void** ppSwapChains,
|
||||
const DXGIX_PRESENTARRAY_PARAMETERS* pPresentParameters)
|
||||
EXTERN_C HRESULT __stdcall DXGIXPresentArray(UINT SyncInterval, UINT PresentImmediateThreshold, UINT Flags,
|
||||
UINT NumSwapChains, void **ppSwapChains,
|
||||
const DXGIX_PRESENTARRAY_PARAMETERS *pPresentParameters)
|
||||
{
|
||||
IMPLEMENT_STUB();
|
||||
return E_NOTIMPL;
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// TODO we can just move this all to Common I believe.
|
||||
|
||||
#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
|
||||
|
||||
#ifdef WDIMPL_API_EXPORTS
|
||||
#define WDIMPL_API __declspec(dllexport)
|
||||
#define WDIMPL_API __declspec(dllexport)
|
||||
#else
|
||||
#define WDIMPL_API __declspec(dllimport)
|
||||
#define WDIMPL_API __declspec(dllimport)
|
||||
#endif
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "../include/WinDurango.Implementation.Native/WinDurangoNative.h"
|
||||
#include <Windows.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
|
||||
DWORD fdwReason,
|
||||
LPVOID lpvReserved)
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,35 +1,41 @@
|
||||
#pragma once
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/base.h>
|
||||
#include "WinDurango.Implementation.WinRT/WinDurangoImplWinRT.h"
|
||||
#include "WinDurango.Common/interfaces/Storage/Directory.h"
|
||||
#include "WinDurango.Implementation.WinRT/Interfaces/Storage/File.h"
|
||||
#include "WinDurango.Implementation.WinRT/WinDurangoImplWinRT.h"
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt;
|
||||
|
||||
/*
|
||||
* I wonder if this is too confusing?
|
||||
*/
|
||||
namespace wd::impl::winrt::interfaces::storage {
|
||||
class WDIMPL_API WinRTDirectory : public wd::common::interfaces::storage::Directory {
|
||||
public:
|
||||
WinRTDirectory(std::filesystem::path dirpath) : path(dirpath), dir(nullptr) {}
|
||||
*/
|
||||
namespace wd::impl::winrt::interfaces::storage
|
||||
{
|
||||
class WDIMPL_API WinRTDirectory : public wd::common::interfaces::storage::Directory
|
||||
{
|
||||
public:
|
||||
WinRTDirectory(std::filesystem::path dirpath) : path(dirpath), dir(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool open() override;
|
||||
virtual std::shared_ptr<wd::common::interfaces::storage::File> CreateFile(std::filesystem::path path) override;
|
||||
virtual std::shared_ptr<wd::common::interfaces::storage::Directory> CreateFolder(std::filesystem::path path) override;
|
||||
virtual std::shared_ptr<wd::common::interfaces::storage::Directory> CreateFolder(
|
||||
std::filesystem::path path) override;
|
||||
|
||||
virtual std::filesystem::path dirpath() override;
|
||||
|
||||
|
||||
virtual bool rename(std::string) override;
|
||||
virtual bool remove() override;
|
||||
virtual bool move(std::filesystem::path path) override;
|
||||
virtual bool copy(std::filesystem::path path) override;
|
||||
private:
|
||||
|
||||
private:
|
||||
std::filesystem::path path;
|
||||
StorageFolder dir;
|
||||
};
|
||||
}
|
||||
} // namespace wd::impl::winrt::interfaces::storage
|
||||
@@ -1,20 +1,24 @@
|
||||
#pragma once
|
||||
#include <istream>
|
||||
#include <filesystem>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/base.h>
|
||||
#include "WinDurango.Implementation.WinRT/WinDurangoImplWinRT.h"
|
||||
#include "WinDurango.Common/Interfaces/Storage/File.h"
|
||||
#include "WinDurango.Implementation.WinRT/WinDurangoImplWinRT.h"
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt;
|
||||
|
||||
namespace wd::impl::winrt::interfaces::storage {
|
||||
class WDIMPL_API WinRTFile : public wd::common::interfaces::storage::File {
|
||||
public:
|
||||
WinRTFile(std::filesystem::path filepath) : path(filepath), file(nullptr) {}
|
||||
namespace wd::impl::winrt::interfaces::storage
|
||||
{
|
||||
class WDIMPL_API WinRTFile : public wd::common::interfaces::storage::File
|
||||
{
|
||||
public:
|
||||
WinRTFile(std::filesystem::path filepath) : path(filepath), file(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool open() override;
|
||||
virtual bool create() override;
|
||||
@@ -24,13 +28,14 @@ namespace wd::impl::winrt::interfaces::storage {
|
||||
|
||||
virtual std::filesystem::path filepath() override;
|
||||
virtual std::filesystem::path fullfilepath() override;
|
||||
|
||||
|
||||
virtual bool rename(std::string) override;
|
||||
virtual bool remove() override;
|
||||
virtual bool move(std::filesystem::path path) override;
|
||||
virtual bool copy(std::filesystem::path path) override;
|
||||
private:
|
||||
|
||||
private:
|
||||
std::filesystem::path path;
|
||||
StorageFile file;
|
||||
};
|
||||
}
|
||||
} // namespace wd::impl::winrt::interfaces::storage
|
||||
@@ -1,13 +1,13 @@
|
||||
#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
|
||||
|
||||
#ifdef WDIMPL_API_EXPORTS
|
||||
#define WDIMPL_API __declspec(dllexport)
|
||||
#define WDIMPL_API __declspec(dllexport)
|
||||
#else
|
||||
#define WDIMPL_API __declspec(dllimport)
|
||||
#define WDIMPL_API __declspec(dllimport)
|
||||
#endif
|
||||
@@ -1,11 +1,12 @@
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include "WinDurangoImplWinRT.h"
|
||||
#include <iostream>
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
* Found here
|
||||
* https://stackoverflow.com/questions/12168113/detect-application-running-in-winrt-mode-by-pid
|
||||
*/
|
||||
bool WDIMPL_API ImplementationSupported() {
|
||||
*/
|
||||
bool WDIMPL_API ImplementationSupported()
|
||||
{
|
||||
return IsImmersiveProcess(GetCurrentProcess());
|
||||
}
|
||||
@@ -3,24 +3,31 @@
|
||||
/*
|
||||
* This is a Dir Class and all the funcs inside
|
||||
* are specifically for managing this dir.
|
||||
*/
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::open() {
|
||||
if (dir != nullptr) {
|
||||
*/
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::open()
|
||||
{
|
||||
if (dir != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder sf = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : path) {
|
||||
for (const auto &part : path)
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
sf = sf.GetFolderAsync(partStr).get();
|
||||
}
|
||||
|
||||
if (sf) {
|
||||
if (sf)
|
||||
{
|
||||
dir = sf;
|
||||
return true;
|
||||
}
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -29,151 +36,199 @@ bool wd::impl::winrt::interfaces::storage::WinRTDirectory::open() {
|
||||
/*
|
||||
* Todo:
|
||||
* Add logging
|
||||
*
|
||||
*
|
||||
* TargetPath is the filename btw
|
||||
* any path will be ignored.
|
||||
*/
|
||||
std::shared_ptr<wd::common::interfaces::storage::File> wd::impl::winrt::interfaces::storage::WinRTDirectory::CreateFile(std::filesystem::path targetPath) {
|
||||
if (dir == nullptr) {
|
||||
*/
|
||||
std::shared_ptr<wd::common::interfaces::storage::File> wd::impl::winrt::interfaces::storage::WinRTDirectory::CreateFile(
|
||||
std::filesystem::path targetPath)
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
auto file = dir.CreateFileAsync(hstring(targetPath.filename().wstring()), CreationCollisionOption::OpenIfExists).get();
|
||||
std::shared_ptr<wd::impl::winrt::interfaces::storage::WinRTFile> fileRT = std::make_shared<wd::impl::winrt::interfaces::storage::WinRTFile>(path / targetPath.filename());
|
||||
try
|
||||
{
|
||||
auto file =
|
||||
dir.CreateFileAsync(hstring(targetPath.filename().wstring()), CreationCollisionOption::OpenIfExists).get();
|
||||
std::shared_ptr<wd::impl::winrt::interfaces::storage::WinRTFile> fileRT =
|
||||
std::make_shared<wd::impl::winrt::interfaces::storage::WinRTFile>(path / targetPath.filename());
|
||||
return fileRT;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Use Shared Pointers
|
||||
*/
|
||||
std::shared_ptr<wd::common::interfaces::storage::Directory> wd::impl::winrt::interfaces::storage::WinRTDirectory::CreateFolder(std::filesystem::path targetPath) {
|
||||
if (dir == nullptr) {
|
||||
*/
|
||||
std::shared_ptr<wd::common::interfaces::storage::Directory> wd::impl::winrt::interfaces::storage::WinRTDirectory::
|
||||
CreateFolder(std::filesystem::path targetPath)
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
auto file = dir.CreateFolderAsync(hstring(targetPath.filename().wstring()), CreationCollisionOption::OpenIfExists).get();
|
||||
std::shared_ptr<wd::impl::winrt::interfaces::storage::WinRTDirectory> folderRT = std::make_shared<wd::impl::winrt::interfaces::storage::WinRTDirectory>(path / targetPath.filename());
|
||||
try
|
||||
{
|
||||
auto file =
|
||||
dir.CreateFolderAsync(hstring(targetPath.filename().wstring()), CreationCollisionOption::OpenIfExists)
|
||||
.get();
|
||||
std::shared_ptr<wd::impl::winrt::interfaces::storage::WinRTDirectory> folderRT =
|
||||
std::make_shared<wd::impl::winrt::interfaces::storage::WinRTDirectory>(path / targetPath.filename());
|
||||
return folderRT;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path wd::impl::winrt::interfaces::storage::WinRTDirectory::dirpath() {
|
||||
std::filesystem::path wd::impl::winrt::interfaces::storage::WinRTDirectory::dirpath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::rename(std::string newName) {
|
||||
if (dir == nullptr) {
|
||||
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::rename(std::string newName)
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
dir.RenameAsync(to_hstring(newName)).get();
|
||||
path.replace_filename(newName);
|
||||
return true;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::remove() {
|
||||
if (dir == nullptr) {
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::remove()
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
dir.DeleteAsync().get();
|
||||
return true;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveFolder(StorageFolder source, StorageFolder destinationContainer) {
|
||||
try {
|
||||
StorageFolder destinationFolder = destinationContainer.CreateFolderAsync(source.Name(), CreationCollisionOption::OpenIfExists).get();
|
||||
bool MoveFolder(StorageFolder source, StorageFolder destinationContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
StorageFolder destinationFolder =
|
||||
destinationContainer.CreateFolderAsync(source.Name(), CreationCollisionOption::OpenIfExists).get();
|
||||
|
||||
for (auto file : source.GetFilesAsync().get()) {
|
||||
for (auto file : source.GetFilesAsync().get())
|
||||
{
|
||||
file.MoveAsync(destinationFolder, file.Name(), NameCollisionOption::GenerateUniqueName).get();
|
||||
}
|
||||
|
||||
for (auto folder : source.GetFoldersAsync().get()) {
|
||||
|
||||
for (auto folder : source.GetFoldersAsync().get())
|
||||
{
|
||||
MoveFolder(folder, destinationFolder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::move(std::filesystem::path targetPath) {
|
||||
if (dir == nullptr) {
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::move(std::filesystem::path targetPath)
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder target = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : targetPath) {
|
||||
for (const auto &part : targetPath)
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
target = target.GetFolderAsync(partStr).get();
|
||||
}
|
||||
|
||||
if (MoveFolder(dir, target)) {
|
||||
if (MoveFolder(dir, target))
|
||||
{
|
||||
path = targetPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CopyFolder(StorageFolder source, StorageFolder destinationContainer) {
|
||||
try {
|
||||
StorageFolder destinationFolder = destinationContainer.CreateFolderAsync(source.Name(), CreationCollisionOption::OpenIfExists).get();
|
||||
bool CopyFolder(StorageFolder source, StorageFolder destinationContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
StorageFolder destinationFolder =
|
||||
destinationContainer.CreateFolderAsync(source.Name(), CreationCollisionOption::OpenIfExists).get();
|
||||
|
||||
for (auto file : source.GetFilesAsync().get()) {
|
||||
for (auto file : source.GetFilesAsync().get())
|
||||
{
|
||||
file.CopyAsync(destinationFolder, file.Name(), NameCollisionOption::GenerateUniqueName).get();
|
||||
}
|
||||
|
||||
for (auto folder : source.GetFoldersAsync().get()) {
|
||||
|
||||
for (auto folder : source.GetFoldersAsync().get())
|
||||
{
|
||||
CopyFolder(folder, destinationFolder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::copy(std::filesystem::path targetPath) {
|
||||
if (dir == nullptr) {
|
||||
bool wd::impl::winrt::interfaces::storage::WinRTDirectory::copy(std::filesystem::path targetPath)
|
||||
{
|
||||
if (dir == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder target = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : targetPath) {
|
||||
for (const auto &part : targetPath)
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
target = target.GetFolderAsync(partStr).get();
|
||||
}
|
||||
|
||||
if (CopyFolder(dir, target)) {
|
||||
if (CopyFolder(dir, target))
|
||||
{
|
||||
path = targetPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (const hresult_error& ex) {
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,53 +1,70 @@
|
||||
#include "interfaces/Storage/File.h"
|
||||
|
||||
namespace wd::impl::winrt::interfaces::storage {
|
||||
bool WinRTFile::open() {
|
||||
if (file != nullptr) {
|
||||
namespace wd::impl::winrt::interfaces::storage
|
||||
{
|
||||
bool WinRTFile::open()
|
||||
{
|
||||
if (file != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder sf = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : path.parent_path()) {
|
||||
for (const auto &part : path.parent_path())
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
sf = sf.GetFolderAsync(partStr).get();
|
||||
}
|
||||
if (!sf) {
|
||||
if (!sf)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StorageFile npFile = sf.GetFileAsync(hstring(path.filename().wstring())).get();
|
||||
file = npFile;
|
||||
if (!npFile) {
|
||||
if (!npFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WinRTFile::create() {
|
||||
if (file != nullptr) {
|
||||
bool WinRTFile::create()
|
||||
{
|
||||
if (file != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder sf = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : path.parent_path()) {
|
||||
for (const auto &part : path.parent_path())
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
sf = sf.GetFolderAsync(partStr).get();
|
||||
}
|
||||
if (!sf) {
|
||||
if (!sf)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file = sf.CreateFileAsync(hstring(path.filename().wstring()), CreationCollisionOption::OpenIfExists).get();
|
||||
if (!file) {
|
||||
if (!file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -55,88 +72,117 @@ namespace wd::impl::winrt::interfaces::storage {
|
||||
/*
|
||||
* btw these docs are pretty useful
|
||||
* https://learn.microsoft.com/en-us/windows/uwp/get-started/fileio-learning-track
|
||||
*/
|
||||
std::string WinRTFile::read() {
|
||||
if (file == nullptr) {
|
||||
*/
|
||||
std::string WinRTFile::read()
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return "Failed";
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
return to_string(FileIO::ReadTextAsync(file).get());
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return "Failed";
|
||||
}
|
||||
return "Failed";
|
||||
}
|
||||
|
||||
void WinRTFile::operator<<(std::string data) {
|
||||
if (file == nullptr) {
|
||||
void WinRTFile::operator<<(std::string data)
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
FileIO::WriteTextAsync(file, to_hstring(data)).get();
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool WinRTFile::close() {
|
||||
if (file == nullptr) {
|
||||
|
||||
bool WinRTFile::close()
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
file = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path WinRTFile::filepath() {
|
||||
std::filesystem::path WinRTFile::filepath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
std::filesystem::path WinRTFile::fullfilepath() {
|
||||
std::filesystem::path WinRTFile::fullfilepath()
|
||||
{
|
||||
StorageFolder sf = ApplicationData::Current().LocalFolder();
|
||||
std::filesystem::path rootPath { sf.Path().c_str() };
|
||||
std::filesystem::path rootPath{sf.Path().c_str()};
|
||||
|
||||
return rootPath / path;
|
||||
}
|
||||
|
||||
bool WinRTFile::rename(std::string name) {
|
||||
if (file == nullptr) {
|
||||
bool WinRTFile::rename(std::string name)
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
file.RenameAsync(to_hstring(name), NameCollisionOption::GenerateUniqueName).get();
|
||||
path.replace_filename(name);
|
||||
return true;
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WinRTFile::remove() {
|
||||
if (file == nullptr) {
|
||||
bool WinRTFile::remove()
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
file.DeleteAsync().get();
|
||||
return true;
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WinRTFile::move(std::filesystem::path targetPath) {
|
||||
if (file == nullptr) {
|
||||
bool WinRTFile::move(std::filesystem::path targetPath)
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder target = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : targetPath.parent_path()) {
|
||||
for (const auto &part : targetPath.parent_path())
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
target = target.GetFolderAsync(partStr).get();
|
||||
}
|
||||
if (!target) {
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,32 +192,41 @@ namespace wd::impl::winrt::interfaces::storage {
|
||||
path = targetPath;
|
||||
path.replace_filename(filename);
|
||||
return true;
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WinRTFile::copy(std::filesystem::path targetPath) {
|
||||
if (file == nullptr) {
|
||||
bool WinRTFile::copy(std::filesystem::path targetPath)
|
||||
{
|
||||
if (file == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try
|
||||
{
|
||||
StorageFolder target = ApplicationData::Current().LocalFolder();
|
||||
|
||||
for (const auto& part : targetPath.parent_path()) {
|
||||
for (const auto &part : targetPath.parent_path())
|
||||
{
|
||||
hstring partStr = hstring(part.wstring());
|
||||
target = target.GetFolderAsync(partStr).get();
|
||||
}
|
||||
if (!target) {
|
||||
if (!target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file.CopyAsync(target).get();
|
||||
return true;
|
||||
} catch (const hresult_error& ex) {
|
||||
}
|
||||
catch (const hresult_error &ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace wd::impl::winrt::interfaces::storage
|
||||
@@ -1,16 +1,15 @@
|
||||
#pragma once
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <windows.h>
|
||||
#include <filesystem>
|
||||
#include <Shlwapi.h>
|
||||
#include <winrt/windows.storage.provider.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <filesystem>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <windows.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/windows.storage.provider.h>
|
||||
|
||||
|
||||
//Provided by XWine1, all credits to them.
|
||||
// Provided by XWine1, all credits to them.
|
||||
//(This is from the old impl but we can use it just fine).
|
||||
HRESULT XWineGetImport(_In_opt_ HMODULE Module, _In_ HMODULE ImportModule, _In_ LPCSTR Import,
|
||||
_Out_ PIMAGE_THUNK_DATA *pThunk);
|
||||
|
||||
@@ -23,11 +23,14 @@
|
||||
#define MEM_PHYSICAL_SIZE 0x400000000ULL // 16 GiB
|
||||
static std::bitset<(MEM_PHYSICAL_SIZE >> 16)> XwpPhysicalPages;
|
||||
static SRWLOCK XwpPhysicalMemoryLock = SRWLOCK_INIT;
|
||||
static HANDLE XwpPhysicalMemory = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE, SEC_RESERVE, MEM_PHYSICAL_SIZE, nullptr, nullptr, 0);
|
||||
static HANDLE XwpPhysicalMemory =
|
||||
CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE, SEC_RESERVE,
|
||||
MEM_PHYSICAL_SIZE, nullptr, nullptr, 0);
|
||||
|
||||
// ESRAM stuff
|
||||
#define MEM_ESRAM_SIZE 0x2000000ULL // 32 MiB
|
||||
static HANDLE XwpEsramMemory = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE, PAGE_READWRITE, SEC_RESERVE, MEM_ESRAM_SIZE, nullptr, nullptr, 0);
|
||||
static HANDLE XwpEsramMemory = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
PAGE_READWRITE, SEC_RESERVE, MEM_ESRAM_SIZE, nullptr, nullptr, 0);
|
||||
|
||||
typedef struct _MAPPABLE_MEM
|
||||
{
|
||||
@@ -211,5 +214,4 @@ CRITICAL_SECTION XmpAllocationHookLock;
|
||||
static PXMEMALLOC_ROUTINE XmpAllocRoutine = XMemAllocDefault;
|
||||
static PXMEMFREE_ROUTINE XmpFreeRoutine = XMemFreeDefault;
|
||||
|
||||
|
||||
#endif // WINDURANGO_KERNEL_H
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Hooks.h"
|
||||
#include "WinDurango.Implementation.WinRT/Interfaces/Storage/Directory.h"
|
||||
#include "WinDurango.Common/Interfaces/Storage/Directory.h"
|
||||
#include "WinDurango.Common/WinDurango.h"
|
||||
#include "WinDurango.Implementation.WinRT/Interfaces/Storage/Directory.h"
|
||||
|
||||
std::shared_ptr<wd::common::WinDurango> winDurango;
|
||||
|
||||
@@ -67,7 +67,8 @@ HRESULT XWinePatchImport(_In_opt_ HMODULE Module, _In_ HMODULE ImportModule, _In
|
||||
DWORD protect;
|
||||
PIMAGE_THUNK_DATA pThunk;
|
||||
HRESULT hr = XWineGetImport(Module, ImportModule, Import, &pThunk);
|
||||
if (FAILED(hr)) return hr;
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (!VirtualProtect(&pThunk->u1.Function, sizeof(ULONG_PTR), PAGE_READWRITE, &protect))
|
||||
return GetLastError();
|
||||
@@ -128,11 +129,13 @@ inline HRESULT WINAPI EraRoGetActivationFactory(HSTRING classId, REFIID iid, voi
|
||||
HRESULT WINAPI GetActivationFactoryRedirect(PCWSTR str, REFIID riid, void **ppFactory)
|
||||
{
|
||||
winDurango = wd::common::WinDurango::GetInstance();
|
||||
if (!winDurango->inited()) {
|
||||
#ifndef CROSS_PLATFORM
|
||||
std::shared_ptr<wd::common::interfaces::storage::Directory> rootDir = std::make_shared<wd::impl::winrt::interfaces::storage::WinRTDirectory>("");
|
||||
winDurango->Init(rootDir);
|
||||
#endif
|
||||
if (!winDurango->inited())
|
||||
{
|
||||
#ifndef CROSS_PLATFORM
|
||||
std::shared_ptr<wd::common::interfaces::storage::Directory> rootDir =
|
||||
std::make_shared<wd::impl::winrt::interfaces::storage::WinRTDirectory>("");
|
||||
winDurango->Init(rootDir);
|
||||
#endif
|
||||
}
|
||||
|
||||
HRESULT hr = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "kernelx.h"
|
||||
#include "Hooks.h"
|
||||
#include "kernelx.h"
|
||||
|
||||
static DWORD ReasonForCall = 0;
|
||||
|
||||
@@ -7,8 +7,7 @@ void KernelxInitialize(HINSTANCE hinstDLL)
|
||||
{
|
||||
if (ReasonForCall == DLL_PROCESS_ATTACH || ReasonForCall == DLL_THREAD_ATTACH)
|
||||
{
|
||||
XWinePatchImport(GetModuleHandleW(nullptr),
|
||||
GetRuntimeModule(),
|
||||
XWinePatchImport(GetModuleHandleW(nullptr), GetRuntimeModule(),
|
||||
"?GetActivationFactoryByPCWSTR@@YAJPEAXAEAVGuid@Platform@@PEAPEAX@Z",
|
||||
GetActivationFactoryRedirect);
|
||||
}
|
||||
@@ -26,7 +25,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return QueueUserAPC(
|
||||
[](ULONG_PTR dwParam) { KernelxInitialize(reinterpret_cast<HINSTANCE>(dwParam)); },
|
||||
GetCurrentThread(), reinterpret_cast<ULONG_PTR>(hModule)) != 0;
|
||||
return QueueUserAPC([](ULONG_PTR dwParam) { KernelxInitialize(reinterpret_cast<HINSTANCE>(dwParam)); },
|
||||
GetCurrentThread(), reinterpret_cast<ULONG_PTR>(hModule)) != 0;
|
||||
}
|
||||
@@ -711,14 +711,16 @@ EXTERN_C HANDLE __stdcall EraCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAcce
|
||||
return LoganHandle;
|
||||
}
|
||||
|
||||
return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
return CreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
}
|
||||
|
||||
EXTERN_C HANDLE __stdcall EraCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
|
||||
{
|
||||
return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
}
|
||||
|
||||
EXTERN_C HANDLE __stdcall EraCreateFile2(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
@@ -747,7 +749,8 @@ EXTERN_C DWORD __stdcall EraGetFileAttributesW(LPCWSTR lpFileName)
|
||||
return GetFileAttributesW(lpFileName);
|
||||
}
|
||||
|
||||
EXTERN_C BOOL __stdcall EraGetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation)
|
||||
EXTERN_C BOOL __stdcall EraGetFileAttributesExW(LPCWSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
|
||||
LPVOID lpFileInformation)
|
||||
{
|
||||
return GetFileAttributesExW(lpFileName, fInfoLevelId, lpFileInformation);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,7 @@ void RefreshWasapiDeviceList()
|
||||
MessageBoxW(nullptr, L"TODO: MMDevAPI::RefreshWasapiDeviceList", L"TODO:", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
|
||||
//PC Exports
|
||||
// PC Exports
|
||||
#define MMDEVAPI_EXPORT(Name) __pragma(comment(linker, "/export:" #Name "=C:\\WINDOWS\\System32\\MMDevAPI." #Name))
|
||||
#define MMDEVAPI_EXPORT_ORDINAL(Name, Ordinal) \
|
||||
__pragma(comment(linker, "/export:" #Name "=C:\\WINDOWS\\System32\\MMDevAPI." #Name ",@" #Ordinal))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "WinDurango.Implementation.WinRT/Interfaces/Storage/Directory.h"
|
||||
#include "WinDurango.Common/Logging.h"
|
||||
#include "WinDurango.Implementation.WinRT/Interfaces/Storage/Directory.h"
|
||||
#include "pch.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace winrt;
|
||||
@@ -15,9 +15,9 @@ using namespace Windows::UI::Composition;
|
||||
|
||||
struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
{
|
||||
CompositionTarget m_target{ nullptr };
|
||||
VisualCollection m_visuals{ nullptr };
|
||||
Visual m_selected{ nullptr };
|
||||
CompositionTarget m_target{nullptr};
|
||||
VisualCollection m_visuals{nullptr};
|
||||
Visual m_selected{nullptr};
|
||||
float2 m_offset{};
|
||||
bool runFirst = true;
|
||||
wd::common::Logging logthing;
|
||||
@@ -31,7 +31,7 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
{
|
||||
}
|
||||
|
||||
void Load(hstring const&)
|
||||
void Load(hstring const &)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
|
||||
}
|
||||
|
||||
void SetWindow(CoreWindow const & window)
|
||||
void SetWindow(CoreWindow const &window)
|
||||
{
|
||||
Compositor compositor;
|
||||
ContainerVisual root = compositor.CreateContainerVisual();
|
||||
@@ -56,16 +56,13 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
m_target.Root(root);
|
||||
m_visuals = root.Children();
|
||||
|
||||
window.PointerPressed({ this, &App::OnPointerPressed });
|
||||
window.PointerMoved({ this, &App::OnPointerMoved });
|
||||
window.PointerPressed({this, &App::OnPointerPressed});
|
||||
window.PointerMoved({this, &App::OnPointerMoved});
|
||||
|
||||
window.PointerReleased([&](auto && ...)
|
||||
{
|
||||
m_selected = nullptr;
|
||||
});
|
||||
window.PointerReleased([&](auto &&...) { m_selected = nullptr; });
|
||||
}
|
||||
|
||||
void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
|
||||
void OnPointerPressed(IInspectable const &, PointerEventArgs const &args)
|
||||
{
|
||||
float2 const point = args.CurrentPoint().Position();
|
||||
|
||||
@@ -74,9 +71,7 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
float3 const offset = visual.Offset();
|
||||
float2 const size = visual.Size();
|
||||
|
||||
if (point.x >= offset.x &&
|
||||
point.x < offset.x + size.x &&
|
||||
point.y >= offset.y &&
|
||||
if (point.x >= offset.x && point.x < offset.x + size.x && point.y >= offset.y &&
|
||||
point.y < offset.y + size.y)
|
||||
{
|
||||
m_selected = visual;
|
||||
@@ -116,18 +111,13 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
logthing.Log("WinDurango.Testing", "Click");
|
||||
}
|
||||
|
||||
void OnPointerMoved(IInspectable const &, PointerEventArgs const & args)
|
||||
void OnPointerMoved(IInspectable const &, PointerEventArgs const &args)
|
||||
{
|
||||
if (m_selected)
|
||||
{
|
||||
float2 const point = args.CurrentPoint().Position();
|
||||
|
||||
m_selected.Offset(
|
||||
{
|
||||
point.x + m_offset.x,
|
||||
point.y + m_offset.y,
|
||||
0.0f
|
||||
});
|
||||
m_selected.Offset({point.x + m_offset.x, point.y + m_offset.y, 0.0f});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,13 +126,8 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
Compositor compositor = m_visuals.Compositor();
|
||||
SpriteVisual visual = compositor.CreateSpriteVisual();
|
||||
|
||||
static Color colors[] =
|
||||
{
|
||||
{ 0xDC, 0x5B, 0x9B, 0xD5 },
|
||||
{ 0xDC, 0xED, 0x7D, 0x31 },
|
||||
{ 0xDC, 0x70, 0xAD, 0x47 },
|
||||
{ 0xDC, 0xFF, 0xC0, 0x00 }
|
||||
};
|
||||
static Color colors[] = {
|
||||
{0xDC, 0x5B, 0x9B, 0xD5}, {0xDC, 0xED, 0x7D, 0x31}, {0xDC, 0x70, 0xAD, 0x47}, {0xDC, 0xFF, 0xC0, 0x00}};
|
||||
|
||||
static unsigned last = 0;
|
||||
unsigned const next = ++last % _countof(colors);
|
||||
@@ -150,14 +135,9 @@ struct App : implements<App, IFrameworkViewSource, IFrameworkView>
|
||||
|
||||
float const BlockSize = 100.0f;
|
||||
|
||||
visual.Size(
|
||||
{
|
||||
BlockSize,
|
||||
BlockSize
|
||||
});
|
||||
visual.Size({BlockSize, BlockSize});
|
||||
|
||||
visual.Offset(
|
||||
{
|
||||
visual.Offset({
|
||||
point.x - BlockSize / 2.0f,
|
||||
point.y - BlockSize / 2.0f,
|
||||
0.0f,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.ApplicationModel.Core.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.UI.Composition.h>
|
||||
#include <winrt/Windows.UI.Core.h>
|
||||
#include <winrt/Windows.UI.Input.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "WinDurango.Common/WinDurango.h"
|
||||
#include <Windows.h>
|
||||
|
||||
extern std::shared_ptr<wd::common::WinDurango> p_wd;
|
||||
@@ -1,17 +1,19 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "Windows.Xbox.Media.GameTransportControls.g.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
struct GameTransportControls : GameTransportControlsT<GameTransportControls> {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
struct GameTransportControls : GameTransportControlsT<GameTransportControls>
|
||||
{
|
||||
GameTransportControls() = default;
|
||||
|
||||
hstring Title();
|
||||
void Title(hstring const& value);
|
||||
void Title(hstring const &value);
|
||||
hstring Subtitle();
|
||||
void Subtitle(hstring const& value);
|
||||
void Subtitle(hstring const &value);
|
||||
winrt::Windows::Xbox::Media::GamePlaybackStatus PlaybackStatus();
|
||||
void PlaybackStatus(winrt::Windows::Xbox::Media::GamePlaybackStatus const& value);
|
||||
void PlaybackStatus(winrt::Windows::Xbox::Media::GamePlaybackStatus const &value);
|
||||
winrt::Windows::Xbox::Media::SoundLevel SoundLevel();
|
||||
bool IsEnabled();
|
||||
void IsEnabled(bool value);
|
||||
@@ -25,11 +27,18 @@ namespace winrt::Windows::Xbox::Media::implementation {
|
||||
void IsViewEnabled(bool value);
|
||||
bool IsBackEnabled();
|
||||
void IsBackEnabled(bool value);
|
||||
winrt::event_token add_ButtonPressed(winrt::Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs> const& handler);
|
||||
void remove_ButtonPressed(winrt::event_token const& token);
|
||||
winrt::event_token add_PropertyChanged(winrt::Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs> const& handler);
|
||||
void remove_PropertyChanged(winrt::event_token const& token);
|
||||
private:
|
||||
winrt::event_token add_ButtonPressed(
|
||||
winrt::Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs> const &handler);
|
||||
void remove_ButtonPressed(winrt::event_token const &token);
|
||||
winrt::event_token add_PropertyChanged(
|
||||
winrt::Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs> const &handler);
|
||||
void remove_PropertyChanged(winrt::event_token const &token);
|
||||
|
||||
private:
|
||||
hstring _title;
|
||||
hstring _subtitle;
|
||||
winrt::Windows::Xbox::Media::GamePlaybackStatus _playbackStatus;
|
||||
@@ -39,7 +48,13 @@ namespace winrt::Windows::Xbox::Media::implementation {
|
||||
bool _isMenuEnabled;
|
||||
bool _isViewEnabled;
|
||||
bool _isBackEnabled;
|
||||
winrt::event<winrt::Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs>> e_ButtonPressedHandler;
|
||||
winrt::event<winrt::Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs>> e_PropertyChangedHandler;
|
||||
winrt::event<winrt::Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs>>
|
||||
e_ButtonPressedHandler;
|
||||
winrt::event<winrt::Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs>>
|
||||
e_PropertyChangedHandler;
|
||||
};
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
@@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "Windows.Xbox.Media.GameTransportControlsButtonPressedEventArgs.g.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
struct GameTransportControlsButtonPressedEventArgs : GameTransportControlsButtonPressedEventArgsT<GameTransportControlsButtonPressedEventArgs> {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
struct GameTransportControlsButtonPressedEventArgs
|
||||
: GameTransportControlsButtonPressedEventArgsT<GameTransportControlsButtonPressedEventArgs>
|
||||
{
|
||||
GameTransportControlsButtonPressedEventArgs() = default;
|
||||
GameTransportControlsButton Button();
|
||||
};
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
@@ -1,10 +1,13 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "Windows.Xbox.Media.GameTransportControlsPropertyChangedEventArgs.g.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
struct GameTransportControlsPropertyChangedEventArgs : GameTransportControlsPropertyChangedEventArgsT<GameTransportControlsPropertyChangedEventArgs> {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
struct GameTransportControlsPropertyChangedEventArgs
|
||||
: GameTransportControlsPropertyChangedEventArgsT<GameTransportControlsPropertyChangedEventArgs>
|
||||
{
|
||||
GameTransportControlsPropertyChangedEventArgs() = default;
|
||||
GameTransportControlsProperty Property();
|
||||
};
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
@@ -4,37 +4,37 @@ std::shared_ptr<wd::common::WinDurango> p_wd;
|
||||
|
||||
/*
|
||||
* https://learn.microsoft.com/en-us/windows/win32/dlls/dllmain
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
|
||||
DWORD fdwReason, // reason for calling function
|
||||
LPVOID lpvReserved ) // reserved
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // handle to DLL module
|
||||
DWORD fdwReason, // reason for calling function
|
||||
LPVOID lpvReserved) // reserved
|
||||
{
|
||||
switch( fdwReason )
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
p_wd = wd::common::WinDurango::GetInstance();
|
||||
p_wd->log.Log("WinDurango::WinRT", "Initialized");
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
if (lpvReserved != nullptr)
|
||||
{
|
||||
break; // do not do cleanup if process termination scenario
|
||||
}
|
||||
|
||||
// Perform any necessary cleanup.
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
if (lpvReserved != nullptr)
|
||||
{
|
||||
break; // do not do cleanup if process termination scenario
|
||||
}
|
||||
|
||||
// Perform any necessary cleanup.
|
||||
break;
|
||||
}
|
||||
return TRUE; // Successful DLL_PROCESS_ATTACH.
|
||||
return TRUE; // Successful DLL_PROCESS_ATTACH.
|
||||
}
|
||||
@@ -1,123 +1,153 @@
|
||||
#include "Windows/Xbox/Media/GameTransportControls.h"
|
||||
#include "WinDurangoWinRT.h"
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
hstring GameTransportControls::Title() {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
hstring GameTransportControls::Title()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Title _out_");
|
||||
return _title;
|
||||
}
|
||||
|
||||
void GameTransportControls::Title(hstring const& value) {
|
||||
|
||||
void GameTransportControls::Title(hstring const &value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Title _in_");
|
||||
_title = value;
|
||||
}
|
||||
|
||||
hstring GameTransportControls::Subtitle() {
|
||||
|
||||
hstring GameTransportControls::Subtitle()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Subtitle _out_");
|
||||
return _subtitle;
|
||||
}
|
||||
|
||||
void GameTransportControls::Subtitle(hstring const& value) {
|
||||
|
||||
void GameTransportControls::Subtitle(hstring const &value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Subtitle _in_");
|
||||
_subtitle = value;
|
||||
}
|
||||
|
||||
winrt::Windows::Xbox::Media::GamePlaybackStatus GameTransportControls::PlaybackStatus() {
|
||||
|
||||
winrt::Windows::Xbox::Media::GamePlaybackStatus GameTransportControls::PlaybackStatus()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: PlaybackStatus _out_");
|
||||
return _playbackStatus;
|
||||
}
|
||||
|
||||
void GameTransportControls::PlaybackStatus(winrt::Windows::Xbox::Media::GamePlaybackStatus const& value) {
|
||||
|
||||
void GameTransportControls::PlaybackStatus(winrt::Windows::Xbox::Media::GamePlaybackStatus const &value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: PlaybackStatus _in_");
|
||||
_playbackStatus = value;
|
||||
}
|
||||
|
||||
Windows::Xbox::Media::SoundLevel GameTransportControls::SoundLevel() {
|
||||
|
||||
Windows::Xbox::Media::SoundLevel GameTransportControls::SoundLevel()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: SoundLevel");
|
||||
return Windows::Xbox::Media::SoundLevel::Unknown;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsEnabled() {
|
||||
|
||||
bool GameTransportControls::IsEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsEnabled _out_");
|
||||
return _isEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsEnabled _in_");
|
||||
_isEnabled = value;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsPlayEnabled() {
|
||||
|
||||
bool GameTransportControls::IsPlayEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsPlayEnabled _out_");
|
||||
return _isPlayEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsPlayEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsPlayEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsPlayEnabled _in_");
|
||||
_isPlayEnabled = value;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsPauseEnabled() {
|
||||
|
||||
bool GameTransportControls::IsPauseEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsPauseEnabled _out_");
|
||||
return _isPauseEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsPauseEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsPauseEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsPauseEnabled _in_");
|
||||
_isPauseEnabled = value;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsMenuEnabled() {
|
||||
|
||||
bool GameTransportControls::IsMenuEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsMenuEnabled _out_");
|
||||
return _isMenuEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsMenuEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsMenuEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsMenuEnabled _in_");
|
||||
_isMenuEnabled = value;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsViewEnabled() {
|
||||
|
||||
bool GameTransportControls::IsViewEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsViewEnabled _out_");
|
||||
return _isViewEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsViewEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsViewEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsViewEnabled _in_");
|
||||
_isViewEnabled = value;
|
||||
}
|
||||
|
||||
bool GameTransportControls::IsBackEnabled() {
|
||||
|
||||
bool GameTransportControls::IsBackEnabled()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsBackEnabled _out_");
|
||||
return _isBackEnabled;
|
||||
}
|
||||
|
||||
void GameTransportControls::IsBackEnabled(bool value) {
|
||||
|
||||
void GameTransportControls::IsBackEnabled(bool value)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: IsBackEnabled _in_");
|
||||
_isBackEnabled = value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dont use EventRegistrationToken
|
||||
* https://stackoverflow.com/questions/63346461/namespace-winrtwindowsfoundationeventregistrationtoken-has-no-member-ev
|
||||
*/
|
||||
winrt::event_token GameTransportControls::add_ButtonPressed(Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs> const& handler) {
|
||||
*/
|
||||
winrt::event_token GameTransportControls::add_ButtonPressed(
|
||||
Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsButtonPressedEventArgs> const &handler)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: add_ButtonPressed");
|
||||
return e_ButtonPressedHandler.add(handler);
|
||||
}
|
||||
|
||||
void GameTransportControls::remove_ButtonPressed(winrt::event_token const& token) {
|
||||
|
||||
void GameTransportControls::remove_ButtonPressed(winrt::event_token const &token)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: remove_ButtonPressed");
|
||||
e_ButtonPressedHandler.remove(token);
|
||||
}
|
||||
|
||||
winrt::event_token GameTransportControls::add_PropertyChanged(Windows::Foundation::TypedEventHandler<winrt::Windows::Xbox::Media::GameTransportControls, winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs> const& handler) {
|
||||
|
||||
winrt::event_token GameTransportControls::add_PropertyChanged(
|
||||
Windows::Foundation::TypedEventHandler<
|
||||
winrt::Windows::Xbox::Media::GameTransportControls,
|
||||
winrt::Windows::Xbox::Media::GameTransportControlsPropertyChangedEventArgs> const &handler)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: add_PropertyChanged");
|
||||
return e_PropertyChangedHandler.add(handler);
|
||||
}
|
||||
|
||||
void GameTransportControls::remove_PropertyChanged(winrt::event_token const& token) {
|
||||
|
||||
void GameTransportControls::remove_PropertyChanged(winrt::event_token const &token)
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: remove_PropertyChanged");
|
||||
e_PropertyChangedHandler.remove(token);
|
||||
}
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "Windows/Xbox/Media/GameTransportControlsButtonPressedEventArgs.h"
|
||||
#include "WinDurangoWinRT.h"
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
GameTransportControlsButton GameTransportControlsButtonPressedEventArgs::Button() {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
GameTransportControlsButton GameTransportControlsButtonPressedEventArgs::Button()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Button");
|
||||
return GameTransportControlsButton::Play;
|
||||
}
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "Windows/Xbox/Media/GameTransportControlsPropertyChangedEventArgs.h"
|
||||
#include "WinDurangoWinRT.h"
|
||||
|
||||
namespace winrt::Windows::Xbox::Media::implementation {
|
||||
GameTransportControlsProperty GameTransportControlsPropertyChangedEventArgs::Property() {
|
||||
namespace winrt::Windows::Xbox::Media::implementation
|
||||
{
|
||||
GameTransportControlsProperty GameTransportControlsPropertyChangedEventArgs::Property()
|
||||
{
|
||||
p_wd->log.Warn("WinDurango::WinRT::Windows::Xbox::Media", "Unimplemented: Property");
|
||||
return GameTransportControlsProperty::Unknown;
|
||||
}
|
||||
}
|
||||
} // namespace winrt::Windows::Xbox::Media::implementation
|
||||
@@ -8,14 +8,14 @@ typedef struct _ETX_FIELD_DESCRIPTOR
|
||||
{
|
||||
UINT8 Type : 5;
|
||||
UINT8 IsLengthField : 1;
|
||||
} ETX_FIELD_DESCRIPTOR, * PETX_FIELD_DESCRIPTOR, * LPETX_FIELD_DESCRIPTOR;
|
||||
} ETX_FIELD_DESCRIPTOR, *PETX_FIELD_DESCRIPTOR, *LPETX_FIELD_DESCRIPTOR;
|
||||
|
||||
typedef struct _ETX_EVENT_DESCRIPTOR
|
||||
{
|
||||
EVENT_DESCRIPTOR EtwDescriptor;
|
||||
LPCSTR Name;
|
||||
LPCSTR SchemaVersion;
|
||||
ETX_FIELD_DESCRIPTOR const* FieldDescriptors;
|
||||
ETX_FIELD_DESCRIPTOR const *FieldDescriptors;
|
||||
UINT8 NumFields;
|
||||
UINT8 UploadEnabled;
|
||||
UINT8 CurrentUploadEnabledState;
|
||||
@@ -26,7 +26,7 @@ typedef struct _ETX_EVENT_DESCRIPTOR
|
||||
UINT8 DefaultLatency;
|
||||
UINT8 CurrentPriority;
|
||||
UINT8 DefaultPriority;
|
||||
} ETX_EVENT_DESCRIPTOR, * PETX_EVENT_DESCRIPTOR, * LPETX_EVENT_DESCRIPTOR;
|
||||
} ETX_EVENT_DESCRIPTOR, *PETX_EVENT_DESCRIPTOR, *LPETX_EVENT_DESCRIPTOR;
|
||||
|
||||
typedef struct _ETX_PROVIDER_DESCRIPTOR
|
||||
{
|
||||
@@ -43,4 +43,4 @@ typedef struct _ETX_PROVIDER_DESCRIPTOR
|
||||
UINT8 DefaultLatency;
|
||||
UINT8 CurrentPriority;
|
||||
UINT8 DefaultPriority;
|
||||
} ETX_PROVIDER_DESCRIPTOR, * PETX_PROVIDER_DESCRIPTOR, * LPETX_PROVIDER_DESCRIPTOR;
|
||||
} ETX_PROVIDER_DESCRIPTOR, *PETX_PROVIDER_DESCRIPTOR, *LPETX_PROVIDER_DESCRIPTOR;
|
||||
@@ -3,12 +3,9 @@
|
||||
|
||||
#include "etwplus.h"
|
||||
|
||||
EXTERN_C ULONG WINAPI EtxEventWrite(
|
||||
_In_ PETX_EVENT_DESCRIPTOR EventDescriptor,
|
||||
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
|
||||
_In_ REGHANDLE RegHandle,
|
||||
_In_ ULONG UserDataCount,
|
||||
_In_opt_ PEVENT_DATA_DESCRIPTOR UserData)
|
||||
EXTERN_C ULONG WINAPI EtxEventWrite(_In_ PETX_EVENT_DESCRIPTOR EventDescriptor,
|
||||
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor, _In_ REGHANDLE RegHandle,
|
||||
_In_ ULONG UserDataCount, _In_opt_ PEVENT_DATA_DESCRIPTOR UserData)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(EventDescriptor);
|
||||
UNREFERENCED_PARAMETER(ProviderDescriptor);
|
||||
@@ -18,10 +15,8 @@ EXTERN_C ULONG WINAPI EtxEventWrite(
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
EXTERN_C void WINAPI EtxFillCommonFields_v7(
|
||||
_Out_ PEVENT_DATA_DESCRIPTOR EventData,
|
||||
_Out_ PUINT8 Scratch,
|
||||
_In_ SIZE_T ScratchSize)
|
||||
EXTERN_C void WINAPI EtxFillCommonFields_v7(_Out_ PEVENT_DATA_DESCRIPTOR EventData, _Out_ PUINT8 Scratch,
|
||||
_In_ SIZE_T ScratchSize)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(EventData);
|
||||
UNREFERENCED_PARAMETER(Scratch);
|
||||
@@ -29,9 +24,7 @@ EXTERN_C void WINAPI EtxFillCommonFields_v7(
|
||||
ZeroMemory(EventData, sizeof(*EventData));
|
||||
}
|
||||
|
||||
EXTERN_C ULONG WINAPI EtxRegister(
|
||||
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
|
||||
_Out_ PREGHANDLE RegHandle)
|
||||
EXTERN_C ULONG WINAPI EtxRegister(_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor, _Out_ PREGHANDLE RegHandle)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ProviderDescriptor);
|
||||
*RegHandle = 0;
|
||||
@@ -46,9 +39,7 @@ EXTERN_C void WINAPI EtxSuspendUploading()
|
||||
{
|
||||
}
|
||||
|
||||
EXTERN_C ULONG WINAPI EtxUnregister(
|
||||
_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor,
|
||||
_In_ PREGHANDLE RegHandle)
|
||||
EXTERN_C ULONG WINAPI EtxUnregister(_In_ PETX_PROVIDER_DESCRIPTOR ProviderDescriptor, _In_ PREGHANDLE RegHandle)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(ProviderDescriptor);
|
||||
UNREFERENCED_PARAMETER(RegHandle);
|
||||
|
||||
Reference in New Issue
Block a user