mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-12 02:08:45 +00:00
3rdparty: Update WIL to v1.0.260126.7
This commit is contained in:
committed by
lightningterror
parent
1ae55e8615
commit
f357fad0ff
Vendored
+108
-44
@@ -20,6 +20,11 @@ Some things that WIL includes to whet your appetite:
|
||||
- [`include/wil/registry.h`](include/wil/registry.h) ([documentation](https://github.com/microsoft/wil/wiki/Registry-Helpers)): Type-safe functions to read from, write to,
|
||||
and watch the registry. Also, registry watchers that can call a lambda function or a callback function
|
||||
you provide whenever a certain tree within the Windows registry changes.
|
||||
- [`include/wil/network.h`](include/wil/network.h): ([documentation](https://github.com/microsoft/wil/wiki/Network-Helpers)) Supports Winsock and network APIs
|
||||
by providing a header-include list which addresses the inter-header include dependendies;
|
||||
provides RAII objects for WSAStartup refcounts as well as the various addrinfo* types
|
||||
returned from the family of getaddrinfo* functions; provides a type-safe class for managing
|
||||
the entire family of sockaddr-related structures.
|
||||
- [`include/wil/result.h`](include/wil/result.h)
|
||||
([documentation](https://github.com/Microsoft/wil/wiki/Error-handling-helpers)):
|
||||
Preprocessor macros to help you check for errors from Windows API functions,
|
||||
@@ -59,70 +64,128 @@ Note that even though WIL is a header-only library, you still need to install th
|
||||
|
||||
To get started contributing to WIL, first make sure that you have:
|
||||
|
||||
* The latest version of [Visual Studio](https://visualstudio.microsoft.com/downloads/) or Build Tools for Visual Studio with the latest MSVC C++ build tools and Address Sanitizer components included.
|
||||
* The latest version of [Visual Studio](https://visualstudio.microsoft.com/downloads/) or Build Tools for Visual Studio with the latest MSVC C++
|
||||
build tools and Address Sanitizer components included. In Visual Studio Installer's Import Configuration tool, pick [.vsconfig](.vsconfig)
|
||||
to the necessary workloads installed.
|
||||
* The most recent [Windows SDK](https://developer.microsoft.com/windows/downloads/windows-sdk)
|
||||
* [Nuget](https://www.nuget.org/downloads) downloaded and added to `PATH`
|
||||
* (`winget install nuget`; see [Install NuGet client tools](https://learn.microsoft.com/nuget/install-nuget-client-tools))
|
||||
* [vcpkg](https://vcpkg.io) available on your system.
|
||||
Follow their [getting started](https://vcpkg.io/en/getting-started) guide to get set up.
|
||||
You'll need to provide the path to vcpkg when initializing with CMake by passing `-DCMAKE_TOOLCHAIN_FILE=[path to vcpkg]/scripts/buildsystems/vcpkg.cmake`.
|
||||
* [Nuget](https://www.nuget.org/downloads) downloaded and added to `PATH` - see [Install NuGet client tools](https://learn.microsoft.com/nuget/install-nuget-client-tools)
|
||||
* [vcpkg](https://vcpkg.io) available on your system. Follow their [getting started](https://vcpkg.io/en/getting-started) guide to get set up. Make sure the `VCKPKG_ROOT` environment variable is set, and the path to `vcpkg.exe` is in your `%PATH%`.
|
||||
* A recent version of [Clang](http://releases.llvm.org/download.html)
|
||||
|
||||
You can install these with WinGet in a console command line:
|
||||
|
||||
```powershell
|
||||
winget install Microsoft.VisualStudio.2022.Community
|
||||
winget install Microsoft.WindowsSDK.10.0.22621
|
||||
winget install Microsoft.NuGet -e
|
||||
winget install Kitware.CMake -e
|
||||
winget install Ninja-build.Ninja -e
|
||||
|
||||
# Select "Add LLVM to the system path for all users"
|
||||
winget install -i llvm.llvm
|
||||
```
|
||||
|
||||
By default, `init.cmd` and `cmake` attempt to find vcpkg's cmake integration toolchain file on their own, by
|
||||
looking in the `VCPKG_ROOT` environment variable. After bootstrapping, you can use `setx` to have this variable
|
||||
across shell sessions. Make sure the directory containing `vcpkg.exe` is in your `PATH`.
|
||||
|
||||
If `VCPKG_ROOT` is not set you can pass its location to CMake or the `init.cmd` script with one of these:
|
||||
|
||||
* `cmake [...] --toolchain [path to vcpkg]/scripts/buildsystems/vcpkg.cmake`
|
||||
* `scripts\init.cmd [...] --vcpkg <path to vcpkg>`
|
||||
|
||||
Note that if you use the `init.cmd` script (mentioned below), this path can be specified or auto-detected if you:
|
||||
1. Manually specify the path to the root of your vcpkg clone via the `-p` or `--vcpkg` argument,
|
||||
1. Have the `VCPKG_ROOT` environment variable set to the root of your vcpkg clone.
|
||||
You can use the `setx` command to have this variable persist across shell sessions,
|
||||
1. Have the path to the root of your vcpkg clone added to your `PATH` (i.e. the path to `vcpkg.exe`), or
|
||||
1. If your vcpkg clone is located at the root of the same drive as your WIL clone (e.g. `C:\vcpkg` if your WIL clone is on the `C:` drive)
|
||||
|
||||
If you are doing any non-trivial work, also be sure to have:
|
||||
## Visual Studio 2022
|
||||
|
||||
* A recent version of [Clang](http://releases.llvm.org/download.html)
|
||||
* (`winget install -i llvm.llvm` and select `Add LLVM to the system path for all users`)
|
||||
Visual Studio 2022 has [fully integrated CMake support](https://learn.microsoft.com/cpp/build/cmake-projects-in-visual-studio). Opening
|
||||
this directory in Visual Studio 2022 uses the default "clang Debug" configurations. Other configurations for "clang Release," "msvc Debug,"
|
||||
and "msvc Release" are available in the Configuration drop-down.
|
||||
|
||||
## Initial configuration
|
||||
Use "Build > Build All" to compile all targets.
|
||||
|
||||
Once everything is installed (you'll need to restart Terminal if you updated `PATH` and don't have [this 2023 fix](https://github.com/microsoft/terminal/pull/14999)), open a VS native command window (e.g. `x64 Native Tools Command Prompt for VS 2022` \[_not_ `Developer Command Prompt for VS2022`]).
|
||||
## Visual Studio Code
|
||||
|
||||
* If you are familiar with CMake you can get started building normally.
|
||||
* Otherwise, or if you prefer to skip all of the boilerplate, you can use the `init.cmd` script in the [scripts](scripts) directory.
|
||||
For example:
|
||||
```cmd
|
||||
C:\wil> scripts\init.cmd -c clang -g ninja -b debug
|
||||
```
|
||||
You can execute `init.cmd --help` for a summary of available options.
|
||||
The `scripts/init_all.cmd` script will run the `init.cmd` script for all combinations of Clang/MSVC and Debug/RelWithDebInfo.
|
||||
Note that for either script, projects will only be generated for the architecture of the current VS command window.
|
||||
Microsoft's [CMake Tools for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) make working
|
||||
in VSCode easy.
|
||||
|
||||
To set up Visual Studio with IntelliSense, see below.
|
||||
If you used the `init.cmd` script, the corresponding build output directory should contain a `compile_commands.json` file that describes the commands used to compile each input file.
|
||||
Some editors such as Visual Studio Code can be configured to use this file to provide better auto-complete, tooltips, etc.
|
||||
Visual Studio Code, in particular should auto-detect the presence of this file and prompt you to use it for better IntelliSense.
|
||||
If you are not auto-prompted, this can be manually configured in the workspace's C/C++ properties under the property name `compileCommands`.
|
||||
1. Start a "Native Tools Command Prompt" (see below)
|
||||
1. Launch VS Code from the prompt, giving it the path to this repo (like `code c:\wil`)
|
||||
3. Use "CMake: Select Configure Preset" to pick `clang`, then "CMake: Select Build Preset" to pick `clang Debug`, then "CMake: Select Build Target" and pick `all`
|
||||
4. Use "CMake: Build" to compile all targets
|
||||
|
||||
### Visual Studio setup
|
||||
## Command Line
|
||||
|
||||
To generate a Visual Studio solution with IntelliSense:
|
||||
```cmd
|
||||
C:\wil> scripts\init.cmd -c msvc -g msbuild
|
||||
Once everything is installed (you'll need to restart Terminal if you updated `PATH` and don't have [this 2023 fix](https://github.com/microsoft/terminal/pull/14999)),
|
||||
open a VS native command window (e.g. `x64 Native Tools Command Prompt for VS 2022` \[_not_ `Developer Command Prompt for VS2022`]).
|
||||
|
||||
You can use a [CMake preset](./CMakePresets.json) to configure the environment:
|
||||
|
||||
```powershell
|
||||
# Configure for clang compiler, then build clang-debug
|
||||
C:\wil> cmake --preset "clang"
|
||||
C:\wil> cmake --build --preset "clang-debug"
|
||||
```
|
||||
|
||||
That will create a `.sln` file in the corresponding `build/` subdirectory (e.g. `build/msvc64debug`).
|
||||
You can open this solution in Visual Studio to develop and build, or you can invoke MSBuild directly.
|
||||
You can also use [`scripts/init.cmd`](./scripts/init.cmd) to pick the configuration:
|
||||
|
||||
> **Important!** When using MSVC as the generator, the build type (`-b` argument to `init.cmd`) is mostly ignored by Visual Studio (since you can change the build type in the IDE), however this selection may still have an impact on project generation due to logic in the CMake files.
|
||||
```cmd
|
||||
C:\wil> scripts\init.cmd -c clang -g ninja -b debug
|
||||
```
|
||||
|
||||
You can also get decent IntelliSense just by opening the repo directory in Visual Studio; VS should auto-detect CMake. You'll have to compile and run tests in a terminal window, though.
|
||||
This script supports using msbuild as the generator/build-tool (pass `-g msbuild`) and the other [`CMAKE_BUILD_TYPE` values](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html)
|
||||
(pass `-b minsizerel`). You can execute `init.cmd --help` for a summary of available options.
|
||||
|
||||
The `scripts/init_all.cmd` script will run the `init.cmd` script for all combinations of Clang/MSVC and Debug/RelWithDebInfo.
|
||||
|
||||
> **Note**: For either script, projects will only be generated for the architecture of the current VS command window.
|
||||
|
||||
## Inner loop
|
||||
|
||||
The scripts use a common directory pattern of `build/$(compiler)$(arch)$(type)` for the build output root. E.g. `build/clang64debug` when using Clang as the compiler, x64 as the architecture, and Debug as the build type. It is this directory where you will want to build from.
|
||||
In Visual Studio 2022, select a startup item (e.g. `witest.exe`) and use "Debug > Start Debugging". Targets will be
|
||||
rebuilt as needed. Use "Build > Rebuild All" to rebuild all tests. Use the Visual Studio Test Explorer to run the
|
||||
tests.
|
||||
|
||||
For example, if you initialized using the command above (`scripts\init.cmd -c clang -g ninja -b debug`), you can build the tests like so:
|
||||
```cmd
|
||||
C:\wil\build\clang64debug> ninja
|
||||
In VS Code, use "CMake: Set Launch/Debug Target" and select a target (e.g. `witest.exe`). Use "CMake: Debug" (default keybind `Shift-F5`)
|
||||
to run the selected test [in VS Code's debugger environment.](https://code.visualstudio.com/docs/cpp/cpp-debug).
|
||||
Switch to [VS Code's "testing" tab,](https://code.visualstudio.com/docs/debugtest/testing) and click the "Run Tests"
|
||||
option.
|
||||
|
||||
For command-line CMake (configured with `cmake --preset ...`) build use, some examples:
|
||||
```powershell
|
||||
# Build for MSVC release, all targets
|
||||
C:\wil> cmake --build --preset "msvc-release"
|
||||
|
||||
# Build only one test (e.g. for improved compile times)
|
||||
C:\wil> cmake --build --preset "msvc-release" --target "witest.noexcept"
|
||||
|
||||
# Clean outputs, then build one target
|
||||
C:\wil> cmake --build --preset "msvc-release" --clean-first --target "witest"
|
||||
|
||||
# Run tests
|
||||
C:\wil> ctest --preset "msvc-release"
|
||||
```
|
||||
Or, if you want to only build a single test (e.g. for improved compile times):
|
||||
```cmd
|
||||
C:\wil\build\clang64debug> ninja witest.noexcept
|
||||
|
||||
For command-line Ninja (configured with `init.cmd -c clang -b debug`) build use, some examples:
|
||||
```powershell
|
||||
# Build all tests
|
||||
C:\wil> ninja -C build\clang-x64-debug
|
||||
|
||||
# Build only one test
|
||||
C:\wil> ninja -C build\clang-x64-debug witest
|
||||
|
||||
# Clean outputs, then build one target
|
||||
C:\wil> ninja -C build\clang-x64-debug -j 0 clean witest.app
|
||||
|
||||
# Run the tests (PowerShell)
|
||||
C:\wil> Get-ChildItem -Recurse -File build\clang-x64-debug\witest*.exe | %{ Write-Host $_ ; & $_ }
|
||||
|
||||
# Run the tests (cmd)
|
||||
C:\wil> for /F %f IN ('dir /s /b build\clang\tests\witest*.exe') do %f
|
||||
```
|
||||
|
||||
The output is a number of test executables. If you used the initialization script(s) mentioned above, or if you followed
|
||||
@@ -131,6 +194,9 @@ which will execute any test executables that have been built, erroring out - and
|
||||
fails. Note that MSBuild will modify the output directory names, so this script is only compatible with using Ninja as the
|
||||
generator.
|
||||
|
||||
> **Note:** The `witest.app` test is significantly slower than the other tests. You can use Test Explorer or the Testing
|
||||
> tab to hide it while doing quick validation.
|
||||
|
||||
## Build everything
|
||||
|
||||
If you are at the tail end of of a change, you can execute the following to get a wide range of coverage:
|
||||
@@ -139,8 +205,6 @@ C:\wil> scripts\init_all.cmd
|
||||
C:\wil> scripts\build_all.cmd
|
||||
C:\wil> scripts\runtests.cmd
|
||||
```
|
||||
Note that this will only test for the architecture that corresponds to the command window you opened. You will want to
|
||||
repeat this process for the other architecture (e.g. by using the `x86 Native Tools Command Prompt for VS 2022` in addition to `x64`).
|
||||
|
||||
## Formatting
|
||||
|
||||
@@ -204,7 +268,7 @@ C:\wil> scripts\run-clang-format.cmd
|
||||
```
|
||||
Additionally, we've added a build target that will invoke this script, named `format`:
|
||||
```cmd
|
||||
C:\wil\build\clang64debug> ninja format
|
||||
C:\wil\build\clang-x64-debug> ninja format
|
||||
```
|
||||
Please note that this all assumes that your Visual Studio installation is up to date.
|
||||
If it's out of date, code unrelated to your changes may get formatted unexpectedly.
|
||||
|
||||
+48
-5
@@ -282,7 +282,7 @@ namespace details
|
||||
return *this;
|
||||
}
|
||||
|
||||
StoredCallContextInfo(StoredCallContextInfo const& other) WI_NOEXCEPT : m_ownsMessage(false)
|
||||
StoredCallContextInfo(StoredCallContextInfo const& other) WI_NOEXCEPT
|
||||
{
|
||||
contextId = other.contextId;
|
||||
contextName = other.contextName;
|
||||
@@ -296,7 +296,7 @@ namespace details
|
||||
}
|
||||
}
|
||||
|
||||
StoredCallContextInfo(_In_opt_ PCSTR staticContextName) WI_NOEXCEPT : m_ownsMessage(false)
|
||||
StoredCallContextInfo(_In_opt_ PCSTR staticContextName) WI_NOEXCEPT
|
||||
{
|
||||
contextId = 0;
|
||||
contextName = staticContextName;
|
||||
@@ -365,7 +365,7 @@ namespace details
|
||||
}
|
||||
}
|
||||
|
||||
bool m_ownsMessage;
|
||||
bool m_ownsMessage{false};
|
||||
};
|
||||
|
||||
template <typename TActivity>
|
||||
@@ -530,8 +530,8 @@ protected:
|
||||
static bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT
|
||||
{
|
||||
static long volatile s_lastFailureSeen = -1;
|
||||
auto wasSeen = (s_lastFailureSeen == failureId);
|
||||
s_lastFailureSeen = failureId;
|
||||
long oldValue = InterlockedExchange(&s_lastFailureSeen, failureId);
|
||||
auto wasSeen = (oldValue == failureId);
|
||||
return wasSeen;
|
||||
}
|
||||
|
||||
@@ -4731,6 +4731,49 @@ WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS")
|
||||
varName8, \
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \
|
||||
TelemetryPrivacyDataTag(PrivacyTag))
|
||||
#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM9( \
|
||||
EventId, \
|
||||
PrivacyTag, \
|
||||
VarType1, \
|
||||
varName1, \
|
||||
VarType2, \
|
||||
varName2, \
|
||||
VarType3, \
|
||||
varName3, \
|
||||
VarType4, \
|
||||
varName4, \
|
||||
VarType5, \
|
||||
varName5, \
|
||||
VarType6, \
|
||||
varName6, \
|
||||
VarType7, \
|
||||
varName7, \
|
||||
VarType8, \
|
||||
varName8, \
|
||||
VarType9, \
|
||||
varName9) \
|
||||
DEFINE_TRACELOGGING_EVENT_PARAM9( \
|
||||
EventId, \
|
||||
VarType1, \
|
||||
varName1, \
|
||||
VarType2, \
|
||||
varName2, \
|
||||
VarType3, \
|
||||
varName3, \
|
||||
VarType4, \
|
||||
varName4, \
|
||||
VarType5, \
|
||||
varName5, \
|
||||
VarType6, \
|
||||
varName6, \
|
||||
VarType7, \
|
||||
varName7, \
|
||||
VarType8, \
|
||||
varName8, \
|
||||
VarType9, \
|
||||
varName9, \
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), \
|
||||
TelemetryPrivacyDataTag(PrivacyTag))
|
||||
|
||||
#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag) \
|
||||
DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag))
|
||||
|
||||
Vendored
+73
-75
@@ -65,20 +65,20 @@ namespace details
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
inline static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result)
|
||||
static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result)
|
||||
{
|
||||
return ptr->QueryInterface(riid, result);
|
||||
}
|
||||
|
||||
template <typename T, typename TResult>
|
||||
inline static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result)
|
||||
static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result)
|
||||
{
|
||||
return query_dispatch(ptr, typename details::is_com_convertible<T*, TResult*>::type(), result);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, typename TResult>
|
||||
inline static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible
|
||||
static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible
|
||||
{
|
||||
*result = ptr;
|
||||
(*result)->AddRef();
|
||||
@@ -86,7 +86,7 @@ namespace details
|
||||
}
|
||||
|
||||
template <typename T, typename TResult>
|
||||
inline static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible
|
||||
static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible
|
||||
{
|
||||
auto hr = ptr->QueryInterface(IID_PPV_ARGS(result));
|
||||
__analysis_assume(SUCCEEDED(hr) || (*result == nullptr));
|
||||
@@ -103,7 +103,7 @@ namespace details
|
||||
class weak_query_policy
|
||||
{
|
||||
public:
|
||||
inline static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result)
|
||||
static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result)
|
||||
{
|
||||
WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference");
|
||||
*result = nullptr;
|
||||
@@ -125,7 +125,7 @@ namespace details
|
||||
}
|
||||
|
||||
template <typename TResult>
|
||||
inline static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result)
|
||||
static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result)
|
||||
{
|
||||
static_assert(!wistd::is_same<IWeakReference, TResult>::value, "Cannot resolve a weak reference to IWeakReference");
|
||||
return query_dispatch(ptr, wistd::is_base_of<IInspectable, TResult>(), result);
|
||||
@@ -161,7 +161,7 @@ namespace details
|
||||
class agile_query_policy
|
||||
{
|
||||
public:
|
||||
inline static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result)
|
||||
static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result) WI_NOEXCEPT
|
||||
{
|
||||
WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference");
|
||||
auto hr = ptr->Resolve(riid, result);
|
||||
@@ -170,7 +170,7 @@ namespace details
|
||||
}
|
||||
|
||||
template <typename TResult>
|
||||
static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result)
|
||||
static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(!wistd::is_same<IAgileReference, TResult>::value, "Cannot resolve a agile reference to IAgileReference");
|
||||
return query(ptr, __uuidof(TResult), reinterpret_cast<void**>(result));
|
||||
@@ -294,14 +294,14 @@ public:
|
||||
//! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter).
|
||||
com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT
|
||||
{
|
||||
return operator=(other.get());
|
||||
return operator=(other.get()); // NOLINT(misc-unconventional-assign-operator): Can't see through function call
|
||||
}
|
||||
|
||||
//! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter).
|
||||
template <class U, typename err, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
|
||||
com_ptr_t& operator=(const com_ptr_t<U, err>& other) WI_NOEXCEPT
|
||||
{
|
||||
return operator=(static_cast<pointer>(other.get()));
|
||||
return operator=(static_cast<pointer>(other.get())); // NOLINT(misc-unconventional-assign-operator): Can't see through function call
|
||||
}
|
||||
|
||||
//! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the parameter).
|
||||
@@ -488,7 +488,7 @@ public:
|
||||
//! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the
|
||||
//! pointer being queried (exception based or fail-fast).
|
||||
template <class U>
|
||||
WI_NODISCARD inline com_ptr_t<U, err_policy> query() const
|
||||
WI_NODISCARD com_ptr_t<U, err_policy> query() const
|
||||
{
|
||||
static_assert(wistd::is_same<void, result>::value, "query requires exceptions or fail fast; use try_query or query_to");
|
||||
return com_ptr_t<U, err_policy>(m_ptr, details::tag_com_query());
|
||||
@@ -617,7 +617,7 @@ public:
|
||||
//! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, failfast or
|
||||
//! error codes) as the pointer being queried.
|
||||
template <class U>
|
||||
WI_NODISCARD inline com_ptr_t<U, err_policy> try_query() const
|
||||
WI_NODISCARD com_ptr_t<U, err_policy> try_query() const
|
||||
{
|
||||
return com_ptr_t<U, err_policy>(m_ptr, details::tag_try_com_query());
|
||||
}
|
||||
@@ -696,7 +696,7 @@ public:
|
||||
//! null. The returned `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling
|
||||
//! form of the pointer being queried (exception based or fail-fast).
|
||||
template <class U>
|
||||
WI_NODISCARD inline com_ptr_t<U, err_policy> copy() const
|
||||
WI_NODISCARD com_ptr_t<U, err_policy> copy() const
|
||||
{
|
||||
static_assert(wistd::is_same<void, result>::value, "copy requires exceptions or fail fast; use the try_copy or copy_to method");
|
||||
return com_ptr_t<U, err_policy>(m_ptr, details::tag_com_copy());
|
||||
@@ -790,7 +790,7 @@ public:
|
||||
//! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same error
|
||||
//! handling policy (exceptions, failfast or error codes) as the pointer being queried.
|
||||
template <class U>
|
||||
WI_NODISCARD inline com_ptr_t<U, err_policy> try_copy() const
|
||||
WI_NODISCARD com_ptr_t<U, err_policy> try_copy() const
|
||||
{
|
||||
return com_ptr_t<U, err_policy>(m_ptr, details::tag_try_com_copy());
|
||||
}
|
||||
@@ -805,7 +805,7 @@ public:
|
||||
//! not specify the type directly to the template.
|
||||
//! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null).
|
||||
template <class U>
|
||||
_Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const
|
||||
_Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const WI_NOEXCEPT
|
||||
{
|
||||
if (m_ptr)
|
||||
{
|
||||
@@ -826,7 +826,7 @@ public:
|
||||
//! on failure or if the source pointer being queried is null.
|
||||
//! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). Querying
|
||||
//! a null pointer will return `false` with a null result.
|
||||
_Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const
|
||||
_Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const WI_NOEXCEPT
|
||||
{
|
||||
if (m_ptr)
|
||||
{
|
||||
@@ -842,33 +842,33 @@ public:
|
||||
|
||||
//! Copy construct from a compatible WRL ComPtr<T>.
|
||||
template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
|
||||
com_ptr_t(const Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT : com_ptr_t(static_cast<pointer>(other.Get()))
|
||||
com_ptr_t(const ::Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT : com_ptr_t(static_cast<pointer>(other.Get()))
|
||||
{
|
||||
}
|
||||
|
||||
//! Move construct from a compatible WRL ComPtr<T>.
|
||||
template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
|
||||
com_ptr_t(Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT : m_ptr(other.Detach())
|
||||
com_ptr_t(::Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT : m_ptr(other.Detach())
|
||||
{
|
||||
}
|
||||
|
||||
//! Assign from a compatible WRL ComPtr<T>.
|
||||
template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
|
||||
com_ptr_t& operator=(const Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT
|
||||
com_ptr_t& operator=(const ::Microsoft::WRL::ComPtr<U>& other) WI_NOEXCEPT
|
||||
{
|
||||
return operator=(static_cast<pointer>(other.Get()));
|
||||
return operator=(static_cast<pointer>(other.Get())); // NOLINT(misc-unconventional-assign-operator): Can't see through function call
|
||||
}
|
||||
|
||||
//! Move assign from a compatible WRL ComPtr<T>.
|
||||
template <class U, class = wistd::enable_if_t<__is_convertible_to(U*, pointer)>>
|
||||
com_ptr_t& operator=(Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT
|
||||
com_ptr_t& operator=(::Microsoft::WRL::ComPtr<U>&& other) WI_NOEXCEPT
|
||||
{
|
||||
attach(other.Detach());
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Swap pointers with a WRL ComPtr<T> to the same interface.
|
||||
void swap(Microsoft::WRL::ComPtr<T>& other) WI_NOEXCEPT
|
||||
void swap(::Microsoft::WRL::ComPtr<T>& other) WI_NOEXCEPT
|
||||
{
|
||||
auto ptr = m_ptr;
|
||||
m_ptr = other.Detach();
|
||||
@@ -876,29 +876,28 @@ public:
|
||||
}
|
||||
|
||||
//! Swap pointers with a rvalue reference to a WRL ComPtr<T> to the same interface.
|
||||
void swap(Microsoft::WRL::ComPtr<T>&& other) WI_NOEXCEPT
|
||||
void swap(::Microsoft::WRL::ComPtr<T>&& other) WI_NOEXCEPT
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
//! @} // WRL compatibility
|
||||
|
||||
public:
|
||||
// Internal Helpers
|
||||
/// @cond
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_ U* ptr, details::tag_com_query) : m_ptr(nullptr)
|
||||
com_ptr_t(_In_ U* ptr, details::tag_com_query) : m_ptr(nullptr)
|
||||
{
|
||||
err_policy::HResult(details::query_policy_t<U>::query(ptr, &m_ptr));
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr)
|
||||
com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr)
|
||||
{
|
||||
details::query_policy_t<U>::query(ptr, &m_ptr);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) : m_ptr(nullptr)
|
||||
com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) : m_ptr(nullptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
@@ -907,7 +906,7 @@ public:
|
||||
}
|
||||
|
||||
template <class U>
|
||||
inline com_ptr_t(_In_opt_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr)
|
||||
com_ptr_t(_In_opt_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
@@ -1030,13 +1029,13 @@ inline bool operator!=(wistd::nullptr_t, const com_ptr_t<TRight, ErrRight>& righ
|
||||
// WRL ComPtr support
|
||||
|
||||
template <typename T, typename ErrLeft>
|
||||
inline void swap(com_ptr_t<T, ErrLeft>& left, Microsoft::WRL::ComPtr<T>& right) WI_NOEXCEPT
|
||||
inline void swap(com_ptr_t<T, ErrLeft>& left, ::Microsoft::WRL::ComPtr<T>& right) WI_NOEXCEPT
|
||||
{
|
||||
left.swap(right);
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(
|
||||
__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*),
|
||||
@@ -1045,7 +1044,7 @@ inline bool operator==(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::W
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(
|
||||
__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*),
|
||||
@@ -1054,37 +1053,37 @@ inline bool operator<(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WR
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator!=(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(left == right));
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator>=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator>=(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(left < right));
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator>(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator>(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (right < left);
|
||||
}
|
||||
|
||||
template <typename TLeft, typename ErrLeft, typename TRight>
|
||||
inline bool operator<=(const com_ptr_t<TLeft, ErrLeft>& left, const Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
inline bool operator<=(const com_ptr_t<TLeft, ErrLeft>& left, const ::Microsoft::WRL::ComPtr<TRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(right < left));
|
||||
}
|
||||
|
||||
template <typename T, typename ErrRight>
|
||||
inline void swap(Microsoft::WRL::ComPtr<T>& left, com_ptr_t<T, ErrRight>& right) WI_NOEXCEPT
|
||||
inline void swap(::Microsoft::WRL::ComPtr<T>& left, com_ptr_t<T, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
right.swap(left);
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator==(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator==(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(
|
||||
__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*),
|
||||
@@ -1093,7 +1092,7 @@ inline bool operator==(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator<(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator<(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(
|
||||
__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*),
|
||||
@@ -1102,25 +1101,25 @@ inline bool operator<(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator!=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator!=(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(left == right));
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator>=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator>=(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(left < right));
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator>(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator>(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (right < left);
|
||||
}
|
||||
|
||||
template <typename TLeft, typename TRight, typename ErrRight>
|
||||
inline bool operator<=(const Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
inline bool operator<=(const ::Microsoft::WRL::ComPtr<TLeft>& left, const com_ptr_t<TRight, ErrRight>& right) WI_NOEXCEPT
|
||||
{
|
||||
return (!(right < left));
|
||||
}
|
||||
@@ -1224,7 +1223,7 @@ inline bool operator<=(TLeft* left, const com_ptr_t<TRight, ErrRight>& right) WI
|
||||
//! forwarding reference template that can be used as an input com pointer. That input com pointer is allowed to be any of:
|
||||
//! * Raw Pointer: `T* com_raw_ptr(T* ptr)`
|
||||
//! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t<T, err>& ptr)`
|
||||
//! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr<T>& ptr)`
|
||||
//! * WRL ComPtr: `T* com_raw_ptr(const ::Microsoft::WRL::ComPtr<T>& ptr)`
|
||||
//! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)`
|
||||
//!
|
||||
//! Which in turn allows code like the following to be written:
|
||||
@@ -1249,7 +1248,7 @@ T* com_raw_ptr(const wil::com_ptr_t<T, err>& ptr)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* com_raw_ptr(const Microsoft::WRL::ComPtr<T>& ptr)
|
||||
T* com_raw_ptr(const ::Microsoft::WRL::ComPtr<T>& ptr)
|
||||
{
|
||||
return ptr.Get();
|
||||
}
|
||||
@@ -1278,9 +1277,9 @@ inline IInspectable* com_raw_ptr(T^ ptr)
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr<T> make_com_ptr(T* p)
|
||||
com_ptr<T> make_com_ptr(T* ptr)
|
||||
{
|
||||
return p;
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1294,9 +1293,9 @@ com_ptr<T> make_com_ptr(T* p)
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr_nothrow<T> make_com_ptr_nothrow(T* p)
|
||||
com_ptr_nothrow<T> make_com_ptr_nothrow(T* ptr)
|
||||
{
|
||||
return p;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
//! Constructs a `com_ptr_failfast` from a raw pointer.
|
||||
@@ -1309,9 +1308,9 @@ com_ptr_nothrow<T> make_com_ptr_nothrow(T* p)
|
||||
//! }
|
||||
//! ~~~
|
||||
template <typename T>
|
||||
com_ptr_failfast<T> make_com_ptr_failfast(T* p)
|
||||
com_ptr_failfast<T> make_com_ptr_failfast(T* ptr)
|
||||
{
|
||||
return p;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
//! @name Stand-alone query helpers
|
||||
@@ -2135,8 +2134,8 @@ namespace details
|
||||
std::tuple<wil::com_ptr_t<Results, error_policy>...> resultTuple;
|
||||
|
||||
std::apply(
|
||||
[i = 0, &multiQis](auto&... a) mutable {
|
||||
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
|
||||
[i = 0, &multiQis](auto&... ptrs) mutable {
|
||||
(ptrs.attach(reinterpret_cast<typename std::remove_reference<decltype(ptrs)>::type::pointer>(multiQis[i++].pItf)), ...);
|
||||
},
|
||||
resultTuple);
|
||||
return std::tuple<HRESULT, decltype(resultTuple)>(hr, std::move(resultTuple));
|
||||
@@ -2163,8 +2162,8 @@ namespace details
|
||||
{
|
||||
hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis);
|
||||
std::apply(
|
||||
[i = 0, &multiQis](auto&... a) mutable {
|
||||
(a.attach(reinterpret_cast<typename std::remove_reference<decltype(a)>::type::pointer>(multiQis[i++].pItf)), ...);
|
||||
[i = 0, &multiQis](auto&... ptrs) mutable {
|
||||
(ptrs.attach(reinterpret_cast<typename std::remove_reference<decltype(ptrs)>::type::pointer>(multiQis[i++].pItf)), ...);
|
||||
},
|
||||
resultTuple);
|
||||
}
|
||||
@@ -2381,9 +2380,9 @@ RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX);
|
||||
*/
|
||||
inline HRESULT stream_size_nothrow(_In_ IStream* stream, _Out_ unsigned long long* value)
|
||||
{
|
||||
STATSTG st{};
|
||||
RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME));
|
||||
*value = st.cbSize.QuadPart;
|
||||
STATSTG info{};
|
||||
RETURN_IF_FAILED(stream->Stat(&info, STATFLAG_NONAME));
|
||||
*value = info.cbSize.QuadPart;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -3207,12 +3206,14 @@ namespace details
|
||||
template <typename TStoredType, typename IEnumType>
|
||||
struct com_iterator
|
||||
{
|
||||
private:
|
||||
using TActualStoredType =
|
||||
wistd::conditional_t<wistd::is_same_v<TStoredType, void>, typename wil::details::com_enumerator_traits<IEnumType>::smart_result, TStoredType>;
|
||||
|
||||
wil::com_ptr<IEnumType> m_enum{};
|
||||
TActualStoredType m_currentValue{};
|
||||
|
||||
public:
|
||||
using smart_result = TActualStoredType;
|
||||
com_iterator(com_iterator&&) = default;
|
||||
com_iterator(com_iterator const&) = default;
|
||||
@@ -3293,7 +3294,7 @@ WI_NODISCARD auto make_range(IEnumXxx* enumPtr)
|
||||
|
||||
struct iterator_range
|
||||
{
|
||||
|
||||
private:
|
||||
static_assert(!wistd::is_same_v<TActualStoredType, void>, "You must specify a type to receive the enumerated objects.");
|
||||
|
||||
// the stored type must be constructible from the output type of the enumerator
|
||||
@@ -3301,9 +3302,11 @@ WI_NODISCARD auto make_range(IEnumXxx* enumPtr)
|
||||
wistd::is_constructible_v<TActualStoredType, typename wil::details::com_enumerator_traits<IEnumXxx>::Result>,
|
||||
"The type you specified cannot be converted to the enumerator's output type.");
|
||||
|
||||
wil::com_ptr<IEnumXxx> m_enumerator{};
|
||||
|
||||
public:
|
||||
using enumerator_type = com_iterator<TActualStoredType, IEnumXxx>;
|
||||
|
||||
wil::com_ptr<IEnumXxx> m_enumerator{};
|
||||
iterator_range(IEnumXxx* enumPtr) : m_enumerator(enumPtr)
|
||||
{
|
||||
}
|
||||
@@ -3323,10 +3326,10 @@ WI_NODISCARD auto make_range(IEnumXxx* enumPtr)
|
||||
}
|
||||
|
||||
template <typename TEnum, typename = wistd::enable_if_t<wil::details::has_next_v<TEnum*>>>
|
||||
auto make_range(const wil::com_ptr<TEnum>& e)
|
||||
auto make_range(const wil::com_ptr<TEnum>& enumerable)
|
||||
{
|
||||
using Enumerated = typename wil::details::com_enumerator_traits<TEnum>::smart_result;
|
||||
return wil::make_range<Enumerated>(e.get());
|
||||
return wil::make_range<Enumerated>(enumerable.get());
|
||||
}
|
||||
|
||||
#ifdef __IShellItemArray_INTERFACE_DEFINED__
|
||||
@@ -3387,18 +3390,13 @@ public:
|
||||
err_policy::LastErrorIfFalse(static_cast<bool>(m_timer));
|
||||
if (m_timer)
|
||||
{
|
||||
FILETIME ft = filetime::get_system_time();
|
||||
ft = filetime::add(ft, filetime::convert_msec_to_100ns(timeoutInMilliseconds));
|
||||
SetThreadpoolTimer(m_timer.get(), &ft, timeoutInMilliseconds, 0);
|
||||
FILETIME target = filetime::get_system_time();
|
||||
target = filetime::add(target, filetime::convert_msec_to_100ns(timeoutInMilliseconds));
|
||||
SetThreadpoolTimer(m_timer.get(), &target, timeoutInMilliseconds, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_out() const
|
||||
{
|
||||
return m_timedOut;
|
||||
}
|
||||
|
||||
operator bool() const noexcept
|
||||
{
|
||||
// All construction calls must succeed to provide us with a non-null m_timer value.
|
||||
@@ -3418,15 +3416,15 @@ private:
|
||||
{
|
||||
// The timer is waited upon during destruction so it is safe to rely on the this pointer in context.
|
||||
com_timeout_t* self = static_cast<com_timeout_t*>(context);
|
||||
if (SUCCEEDED(CoCancelCall(self->m_threadId, 0)))
|
||||
{
|
||||
self->m_timedOut = true;
|
||||
}
|
||||
|
||||
// There may not be an in-flight call to a marshaled COM function, so this may fail. We also don't synchronize
|
||||
// with other threads, so success/failure can't reliably be communicated to the thread that owns this object, so
|
||||
// we just ignore the result.
|
||||
(void)::CoCancelCall(self->m_threadId, 0);
|
||||
}
|
||||
|
||||
wil::unique_call<decltype(&details::CoDisableCallCancellationNull), details::CoDisableCallCancellationNull, false> m_ensureDisable{};
|
||||
wil::unique_call<decltype(&details::CoDisableCallCancellationNull), details::CoDisableCallCancellationNull, false> m_ensureDisable;
|
||||
DWORD m_threadId{};
|
||||
bool m_timedOut{};
|
||||
|
||||
// The threadpool timer goes last so that it destructs first, waiting until the timer callback has completed.
|
||||
wil::unique_threadpool_timer_nocancel m_timer;
|
||||
|
||||
+45
-41
@@ -149,6 +149,7 @@ namespace details
|
||||
template <apartment_variable_leak_action leak_action = apartment_variable_leak_action::fail_fast, typename test_hook = apartment_variable_platform>
|
||||
struct apartment_variable_base
|
||||
{
|
||||
protected:
|
||||
inline static winrt::slim_mutex s_lock;
|
||||
|
||||
struct apartment_variable_storage
|
||||
@@ -169,6 +170,50 @@ namespace details
|
||||
// Apartment id -> variables storage.
|
||||
inline static wil::object_without_destructor_on_shutdown<std::unordered_map<unsigned long long, apartment_variable_storage>> s_apartmentStorage;
|
||||
|
||||
// NOTE: Requires 's_lock' to be held
|
||||
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;
|
||||
}
|
||||
|
||||
// NOTE: Requires 's_lock' to be held
|
||||
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;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr apartment_variable_base() = default;
|
||||
~apartment_variable_base()
|
||||
{
|
||||
@@ -226,47 +271,6 @@ namespace details
|
||||
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)
|
||||
|
||||
Vendored
+197
-23
@@ -83,8 +83,76 @@
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
#if defined(__MINGW32__) && !defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
using __wchar_t = wchar_t;
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
#include <sal.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#ifndef _Post_z_
|
||||
#ifdef __z
|
||||
#define _Post_z_ SAL__post SAL__valid __z
|
||||
#else
|
||||
#define _Post_z_ SAL__post SAL__valid
|
||||
#endif
|
||||
#endif
|
||||
#ifndef _Pre_maybenull_
|
||||
#define _Pre_maybenull_ SAL__pre SAL__maybenull
|
||||
#endif
|
||||
#ifndef _Translates_last_error_to_HRESULT_
|
||||
#define _Translates_last_error_to_HRESULT_
|
||||
#endif
|
||||
#ifndef _Translates_Win32_to_HRESULT_
|
||||
#define _Translates_Win32_to_HRESULT_(x)
|
||||
#endif
|
||||
#ifndef _Translates_NTSTATUS_to_HRESULT_
|
||||
#define _Translates_NTSTATUS_to_HRESULT_(x)
|
||||
#endif
|
||||
#ifndef _Pre_opt_valid_
|
||||
#define _Pre_opt_valid_ SAL__pre SAL__valid SAL__maybenull
|
||||
#endif
|
||||
#ifndef _Frees_ptr_
|
||||
#define _Frees_ptr_ __drv_freesMem(Mem)
|
||||
#endif
|
||||
#ifndef _Frees_ptr_opt_
|
||||
#define _Frees_ptr_opt_ __drv_freesMem(Mem) SAL__maybenull
|
||||
#endif
|
||||
#ifndef _Pre_valid_
|
||||
#define _Pre_valid_ SAL__pre SAL__valid
|
||||
#endif
|
||||
#ifndef _Ret_opt_bytecap_
|
||||
#define _Ret_opt_bytecap_(n)
|
||||
#endif
|
||||
extern "C"
|
||||
{
|
||||
inline void WriteRelease(long* p, long v)
|
||||
{
|
||||
__atomic_store_n(p, v, __ATOMIC_RELEASE);
|
||||
}
|
||||
inline long ReadAcquire(const long* p)
|
||||
{
|
||||
return __atomic_load_n(p, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
inline long InterlockedIncrementNoFence(volatile long* ptr)
|
||||
{
|
||||
return __atomic_add_fetch(ptr, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
inline long InterlockedDecrementNoFence(volatile long* ptr)
|
||||
{
|
||||
return __atomic_sub_fetch(ptr, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
#if !__has_builtin(_ReturnAddress)
|
||||
inline void* _ReturnAddress(void)
|
||||
{
|
||||
return __builtin_return_address(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can
|
||||
// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to
|
||||
// basic macros without the function for common use cases.
|
||||
@@ -263,7 +331,11 @@
|
||||
#include "wistd_type_traits.h"
|
||||
|
||||
//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code
|
||||
#if defined(_MSC_VER)
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN))
|
||||
#else
|
||||
#define WI_ODR_PRAGMA(NAME, TOKEN)
|
||||
#endif
|
||||
|
||||
#ifdef WIL_KERNEL_MODE
|
||||
WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1")
|
||||
@@ -398,6 +470,15 @@ 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
|
||||
|
||||
#ifdef __has_cpp_attribute
|
||||
#if __has_cpp_attribute(nodiscard) >= 201907L
|
||||
#define WI_NODISCARD_REASON(x) [[nodiscard(x)]]
|
||||
#endif
|
||||
#endif
|
||||
#ifndef WI_NODISCARD_REASON
|
||||
#define WI_NODISCARD_REASON(x) WI_NODISCARD
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
@@ -455,6 +536,21 @@ check fails as opposed to the invalid parameter handler that the STL invokes. Th
|
||||
//! ~~~~
|
||||
//! @{
|
||||
|
||||
namespace wil
|
||||
{
|
||||
/// @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 constexpr unsigned long long value = flag;
|
||||
};
|
||||
} // namespace details
|
||||
} // namespace wil
|
||||
/// @endcond
|
||||
|
||||
//! 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`
|
||||
@@ -560,20 +656,26 @@ The above example is used within WIL to decide whether or not the library contai
|
||||
desktop APIs. Building this functionality as `#IFDEF`s within functions would create ODR violations, whereas
|
||||
doing it with global function pointers and header initialization allows a runtime determination. */
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn)
|
||||
#elif defined(_M_IX86)
|
||||
#elif defined(_M_IX86) || defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#if defined(_MSC_VER)
|
||||
#ifdef _M_IX86
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, fn) \
|
||||
extern "C" \
|
||||
{ \
|
||||
__declspec(selectany) unsigned char g_header_init_##name = static_cast<unsigned char>(fn()); \
|
||||
} \
|
||||
__pragma(comment(linker, "/INCLUDE:_g_header_init_" #name))
|
||||
#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
|
||||
#else
|
||||
#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))
|
||||
#endif
|
||||
#else
|
||||
#define WI_HEADER_INITIALIZATION_FUNCTION(name, expr) inline int name##_header_init = ((expr)(), 0)
|
||||
#endif
|
||||
#else
|
||||
#error linker pragma must include g_header_init variation
|
||||
#endif
|
||||
@@ -594,6 +696,7 @@ namespace details
|
||||
class pointer_range
|
||||
{
|
||||
public:
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param): These should be pointers
|
||||
pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_)
|
||||
{
|
||||
}
|
||||
@@ -620,6 +723,7 @@ for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { }
|
||||
template <typename T>
|
||||
details::pointer_range<T> make_range(T begin, T end)
|
||||
{
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param): These are expected to be pointers and cheap to copy
|
||||
return details::pointer_range<T>(begin, end);
|
||||
}
|
||||
|
||||
@@ -686,18 +790,6 @@ struct variadic_logical_or<false, Rest...> : variadic_logical_or<Rest...>::type
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
template <unsigned long long flag>
|
||||
struct verify_single_flag_helper
|
||||
{
|
||||
static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found");
|
||||
static const unsigned long long value = flag;
|
||||
};
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
|
||||
//! @defgroup typesafety Type Validation
|
||||
//! Helpers to validate variable types to prevent accidental, but allowed type conversions.
|
||||
//! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types
|
||||
@@ -712,32 +804,32 @@ 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
|
||||
_Post_satisfies_(return == static_cast<bool>(val)) constexpr bool verify_bool(const T& val) WI_NOEXCEPT
|
||||
{
|
||||
return static_cast<bool>(val);
|
||||
}
|
||||
|
||||
template <typename T, __R_ENABLE_IF_IS_NOT_CLASS(T)>
|
||||
inline constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT
|
||||
constexpr bool verify_bool(T /*val*/) WI_NOEXCEPT
|
||||
{
|
||||
static_assert(!wistd::is_same<T, T>::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == val) inline constexpr bool verify_bool<bool>(bool val) WI_NOEXCEPT
|
||||
_Post_satisfies_(return == val) constexpr bool verify_bool<bool>(bool val) WI_NOEXCEPT
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<int>(int val) WI_NOEXCEPT
|
||||
_Post_satisfies_(return == (val != 0)) constexpr bool verify_bool<int>(int val) WI_NOEXCEPT
|
||||
{
|
||||
return (val != 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
_Post_satisfies_(return == (val != 0)) inline constexpr bool verify_bool<unsigned char>(unsigned char val) WI_NOEXCEPT
|
||||
_Post_satisfies_(return == (val != 0)) constexpr bool verify_bool<unsigned char>(unsigned char val) WI_NOEXCEPT
|
||||
{
|
||||
return (val != 0);
|
||||
}
|
||||
@@ -748,7 +840,7 @@ 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
|
||||
_Post_satisfies_(return == val) 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");
|
||||
@@ -777,7 +869,7 @@ RETURN_HR_IF(static_cast<HRESULT>(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPat
|
||||
@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
|
||||
_Post_satisfies_(return == hr) 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");
|
||||
@@ -837,11 +929,11 @@ 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))( \
|
||||
(__WI_PUSH_WARNINGS __WI_MSVC_DISABLE_WARNING(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)))
|
||||
: static_cast<unsigned long long>(val)) __WI_POP_WARNINGS)
|
||||
#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))
|
||||
|
||||
@@ -912,6 +1004,88 @@ 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);
|
||||
|
||||
/** A helper tag type used to disambiguate function overloads by assigning priority to each overload.
|
||||
This is primarily useful when using SFINAE on different properties of a type that might overlap. For example, consider
|
||||
the following code:
|
||||
~~~
|
||||
template <typename T, std::enable_if_t<condition_a<T>, int> = 0>
|
||||
void doit(const T&);
|
||||
template <typename T, std::enable_if_t<condition_b<T>, int> = 0>
|
||||
void doit(const T&);
|
||||
~~~
|
||||
If `doit` is called with a type `T` that satisfies both `condition_a<T>` and `condition_b<T>`, the code will fail to
|
||||
compile. One way to solve this issue is to change the condiiton of the second overload to
|
||||
`condition_b<T> && !condition_a<T>`, however this can get quite complicated and verbose fast. With `priority_tag`, this
|
||||
could get simplified down to:
|
||||
~~~
|
||||
template <typename T, std::enable_if_t<condition_a<T>, int> = 0>
|
||||
void doit_impl(const T&, priority_tag<1>);
|
||||
template <typename T, std::enable_if_t<condition_b<T>, int> = 0>
|
||||
void doit_impl(const T&, priority_tag<0>);
|
||||
|
||||
template <typename T>
|
||||
void doit(const T& val)
|
||||
{
|
||||
doit_impl(val, priority_tag<1>{});
|
||||
}
|
||||
~~~
|
||||
This will invoke the first overload if a type `T` satisfies both `condition_a<T>` and `condition_b<T>`.
|
||||
*/
|
||||
template <int N>
|
||||
struct priority_tag : priority_tag<N - 1>
|
||||
{
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <>
|
||||
struct priority_tag<0>
|
||||
{
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// Helper type to determine if a type "behaves like a std::basic_string_view." Note that this type is designed to
|
||||
// match types such as std::basic_string_view, std::basic_string, and winrt::hstring while _not_ matching against
|
||||
// things like std::array or std::vector.
|
||||
template <typename T, typename CharT>
|
||||
struct is_string_view_like_t
|
||||
{
|
||||
private:
|
||||
// winrt::hstring doesn't have much to differentiate itself from std::array/std::vector apart from 'c_str' which
|
||||
// std::basic_string_view lacks. Therefore we need an "OR" condition to get the behavior we want
|
||||
template <typename U>
|
||||
static wistd::true_type has_cstr(
|
||||
U* ptr, wistd::enable_if_t<wistd::is_convertible_v<decltype(ptr->c_str()), wistd::add_const_t<CharT>*>>*);
|
||||
template <typename U>
|
||||
static wistd::false_type has_cstr(U* ptr, ...);
|
||||
|
||||
template <typename U>
|
||||
static wistd::true_type has_substr(U* ptr, wistd::enable_if_t<wistd::is_same_v<decltype(ptr->substr(0, 0)), U>>*);
|
||||
template <typename U>
|
||||
static wistd::false_type has_substr(U*, ...);
|
||||
|
||||
template <typename U>
|
||||
static wistd::true_type test(
|
||||
U* obj,
|
||||
wistd::enable_if_t<wistd::is_same_v<typename U::value_type, CharT>>*, // T::value_type == CharT
|
||||
wistd::enable_if_t<wistd::is_convertible_v<decltype(obj->size()), size_t>>*, // T::size() well formed and convertible to size_t
|
||||
wistd::enable_if_t<wistd::is_convertible_v<decltype(obj->data()), wistd::add_const_t<CharT>*>>*, // T::data() well formed and convertible to const CharT*
|
||||
wistd::enable_if_t<decltype(has_cstr<U>(nullptr, nullptr))::value || decltype(has_substr<U>(nullptr, nullptr))::value>*); // T::c_str() or T::substr() well formed
|
||||
|
||||
template <typename U>
|
||||
static wistd::false_type test(U*, ...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(test<T>(nullptr, nullptr, nullptr, nullptr, nullptr))::value;
|
||||
};
|
||||
|
||||
template <typename T, typename CharT>
|
||||
constexpr bool is_string_view_like = is_string_view_like_t<T, CharT>::value;
|
||||
} // namespace details
|
||||
/// @endcond
|
||||
} // namespace wil
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
+18
-5
@@ -328,7 +328,7 @@ struct result_holder
|
||||
result_holder(result_holder const&) = delete;
|
||||
void operator=(result_holder const&) = delete;
|
||||
|
||||
~result_holder() noexcept(false)
|
||||
~result_holder() noexcept
|
||||
{
|
||||
if (restricted_error && g_pfnDestroyRestrictedErrorInformation)
|
||||
{
|
||||
@@ -342,10 +342,9 @@ struct result_holder
|
||||
result.wrap.~result_wrapper();
|
||||
break;
|
||||
case result_status::error:
|
||||
// Rethrow unobserved exception. Delete this line to
|
||||
// discard unobserved exceptions.
|
||||
if (result.error)
|
||||
std::rethrow_exception(result.error);
|
||||
// Discard unobserved exception. There is nowhere to report it,
|
||||
// and abandonment might validly happen if an exception occurs
|
||||
// before the owner of the task can await it.
|
||||
result.error.~exception_ptr();
|
||||
}
|
||||
}
|
||||
@@ -532,11 +531,25 @@ struct task_promise : promise_base<T>
|
||||
this->emplace_value(wistd::forward<U>(value));
|
||||
}
|
||||
|
||||
// Workaround a bug in MSVC where it does not properly deduce the return type.
|
||||
// Using a constraint is simpler and does not have the issue.
|
||||
#if _HAS_CXX20
|
||||
|
||||
void return_value(T const& value)
|
||||
requires(!wistd::is_reference_v<T>)
|
||||
{
|
||||
this->emplace_value(value);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Dummy = void>
|
||||
wistd::enable_if_t<!wistd::is_reference_v<T>, Dummy> return_value(T const& value)
|
||||
{
|
||||
this->emplace_value(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template <>
|
||||
|
||||
+14
-8
@@ -14,7 +14,11 @@
|
||||
#define __WIL_CPPWINRT_INCLUDED
|
||||
|
||||
#include "common.h"
|
||||
#ifdef __MINGW32__
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include <unknwn.h>
|
||||
#include <inspectable.h>
|
||||
#include <hstring.h>
|
||||
@@ -31,7 +35,7 @@ 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)
|
||||
constexpr int version_from_string(const char* versionString)
|
||||
{
|
||||
int result = 0;
|
||||
while ((*versionString >= '0') && (*versionString <= '9'))
|
||||
@@ -43,12 +47,12 @@ inline constexpr int version_from_string(const char* versionString)
|
||||
return result;
|
||||
}
|
||||
|
||||
inline constexpr int major_version_from_string(const char* versionString)
|
||||
constexpr int major_version_from_string(const char* versionString)
|
||||
{
|
||||
return version_from_string(versionString);
|
||||
}
|
||||
|
||||
inline constexpr int minor_version_from_string(const char* versionString)
|
||||
constexpr int minor_version_from_string(const char* versionString)
|
||||
{
|
||||
int dotCount = 0;
|
||||
while ((*versionString != '\0'))
|
||||
@@ -101,10 +105,12 @@ static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2,
|
||||
// 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
|
||||
// NOLINTBEGIN(readability-redundant-declaration)
|
||||
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;
|
||||
// NOLINTEND(readability-redundant-declaration)
|
||||
/// @endcond
|
||||
|
||||
/// @cond
|
||||
@@ -314,9 +320,9 @@ inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectabl
|
||||
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;
|
||||
T result{nullptr}; // `T` is a projected type.
|
||||
winrt::check_hresult(from->QueryInterface(winrt::guid_of<T>(), winrt::put_abi(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
// For obtaining an object from an interop method on the factory. Example:
|
||||
@@ -333,9 +339,9 @@ auto capture_interop(HRESULT (__stdcall Interface::*method)(InterfaceArgs...), A
|
||||
// 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)
|
||||
auto capture_interop(winrt::Windows::Foundation::IUnknown const& obj, HRESULT (__stdcall Interface::*method)(InterfaceArgs...), Args&&... args)
|
||||
{
|
||||
return winrt::capture<WinRTResult>(o.as<Interface>(), method, std::forward<Args>(args)...);
|
||||
return winrt::capture<WinRTResult>(obj.as<Interface>(), method, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Holds a reference to the host C++/WinRT module to prevent it from being unloaded.
|
||||
|
||||
@@ -111,6 +111,89 @@ struct single_threaded_rw_property : single_threaded_property<T>
|
||||
|
||||
#endif // __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED
|
||||
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_ICLASSFACTORY) && defined(__IClassFactory_INTERFACE_DEFINED__)) || \
|
||||
defined(WIL_DOXYGEN) // class factory
|
||||
/// @cond
|
||||
#define __WIL_CPPWINRT_AUTHORING_INCLUDED_ICLASSFACTORY
|
||||
/// @endcond
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
struct class_factory : winrt::implements<class_factory<T, Rest...>, IClassFactory, winrt::no_weak_ref, Rest...>
|
||||
{
|
||||
HRESULT __stdcall CreateInstance(IUnknown* outer, GUID const& iid, void** result) noexcept final
|
||||
try
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
if (!outer)
|
||||
{
|
||||
return winrt::make_self<T>().as(iid, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CLASS_E_NOAGGREGATION;
|
||||
}
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
HRESULT __stdcall LockServer(BOOL lock) noexcept final
|
||||
try
|
||||
{
|
||||
if (lock)
|
||||
{
|
||||
++winrt::get_module_lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
--winrt::get_module_lock();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
};
|
||||
|
||||
#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_ICLASSFACTORY) && defined(__IClassFactory_INTERFACE_DEFINED__)
|
||||
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_COM_SERVER) && defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_ICLASSFACTORY) && defined(__WIL__COMBASEAPI_H_)) || \
|
||||
defined(WIL_DOXYGEN) // COM server
|
||||
/// @cond
|
||||
#define __WIL_CPPWINRT_AUTHORING_INCLUDED_COM_SERVER
|
||||
/// @endcond
|
||||
|
||||
template <typename T>
|
||||
WI_NODISCARD_REASON("The class is unregistered when the returned value is destructed")
|
||||
unique_com_class_object_cookie
|
||||
register_com_server(GUID const& guid, DWORD context = CLSCTX_LOCAL_SERVER, DWORD flags = REGCLS_MULTIPLEUSE)
|
||||
{
|
||||
unique_com_class_object_cookie registration;
|
||||
winrt::check_hresult(CoRegisterClassObject(
|
||||
guid, winrt::make<class_factory<T, winrt::no_module_lock>>().get(), context, flags, registration.put()));
|
||||
return registration;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
WI_NODISCARD_REASON("The classes are unregistered when the returned value is destructed")
|
||||
std::vector<unique_com_class_object_cookie> register_com_server(
|
||||
std::array<GUID, sizeof...(Ts)> const& guids, DWORD context = CLSCTX_LOCAL_SERVER, DWORD flags = REGCLS_MULTIPLEUSE)
|
||||
{
|
||||
std::vector<wil::unique_com_class_object_cookie> registrations;
|
||||
registrations.reserve(sizeof...(Ts));
|
||||
|
||||
std::size_t i = 0;
|
||||
(registrations.push_back(wil::register_com_server<Ts>(guids[i++], context, flags | REGCLS_SUSPENDED)), ...);
|
||||
|
||||
// allow the user to keep class objects suspended if they've explicitly passed REGCLS_SUSPENDED.
|
||||
if (!WI_IsFlagSet(flags, REGCLS_SUSPENDED))
|
||||
{
|
||||
winrt::check_hresult(CoResumeClassObjects());
|
||||
}
|
||||
|
||||
return registrations;
|
||||
}
|
||||
|
||||
#endif // (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_COM_SERVER) && defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_ICLASSFACTORY) && defined(__WIL__COMBASEAPI_H_))
|
||||
|
||||
#if (!defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H)) || \
|
||||
defined(WIL_DOXYGEN) // WinRT / XAML helpers
|
||||
/// @cond
|
||||
|
||||
+21
-2
@@ -977,7 +977,21 @@ namespace details
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
wistd::unique_ptr<char[]> resultHolder(new (std::nothrow) char[allocationSize]);
|
||||
// NOTE: We need to use '::operator new' here because we return as 'unique_ptr<T>' instead of 'unique_ptr<T[]>'
|
||||
// and 'delete' is incompatible with 'new[]' (say, if we allocate an array of bytes with 'char[]'). Note that it
|
||||
// _is_ valid to allocate with '::operator new' and deallocate with 'delete ptr' so long as the type of 'ptr'
|
||||
// does not have class-specific allocation functions and 'ptr' points to an object of the specified type.
|
||||
|
||||
// default_delete does not handle pointer-to-void
|
||||
struct void_deleter
|
||||
{
|
||||
void operator()(void* ptr) WI_NOEXCEPT
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
wistd::unique_ptr<void, void_deleter> resultHolder(::operator new(allocationSize, std::nothrow));
|
||||
RETURN_IF_NULL_ALLOC(resultHolder);
|
||||
|
||||
for (;;)
|
||||
@@ -993,7 +1007,7 @@ namespace details
|
||||
if (lastError == ERROR_MORE_DATA)
|
||||
{
|
||||
allocationSize *= 2;
|
||||
resultHolder.reset(new (std::nothrow) char[allocationSize]);
|
||||
resultHolder.reset(::operator new(allocationSize, std::nothrow));
|
||||
RETURN_IF_NULL_ALLOC(resultHolder);
|
||||
}
|
||||
else if (lastError == ERROR_NO_MORE_FILES) // for folder enumeration cases
|
||||
@@ -1028,6 +1042,11 @@ RETURN_IF_FAILED(GetFileInfoNoThrow<FileNameInfo>(fileHandle, fileNameInfo));
|
||||
template <FILE_INFO_BY_HANDLE_CLASS infoClass, typename wistd::enable_if<!details::MapInfoClassToInfoStruct<infoClass>::isFixed, int>::type = 0>
|
||||
HRESULT GetFileInfoNoThrow(HANDLE fileHandle, wistd::unique_ptr<typename details::MapInfoClassToInfoStruct<infoClass>::type>& result) WI_NOEXCEPT
|
||||
{
|
||||
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
|
||||
static_assert(
|
||||
__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(typename details::MapInfoClassToInfoStruct<infoClass>::type),
|
||||
"Memory allocated by 'details::GetFileInfo' may not be aligned correctly");
|
||||
#endif
|
||||
void* rawResult;
|
||||
HRESULT hr = details::GetFileInfo(
|
||||
fileHandle,
|
||||
|
||||
+42
-39
@@ -16,7 +16,7 @@
|
||||
#include "common.h"
|
||||
|
||||
#if WIL_USE_STL
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -27,7 +27,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __MINGW32__
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include "resource.h"
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
@@ -66,6 +70,12 @@ namespace reg
|
||||
|
||||
// Open key for reading and writing. Equivalent to KEY_ALL_ACCESS.
|
||||
readwrite,
|
||||
|
||||
// Open key for reading from 64-bit registry.
|
||||
read64,
|
||||
|
||||
// Open key for reading and writing from 64-bit registry. Equivalent to KEY_ALL_ACCESS.
|
||||
readwrite64,
|
||||
};
|
||||
|
||||
/// @cond
|
||||
@@ -101,6 +111,10 @@ namespace reg
|
||||
return KEY_READ;
|
||||
case key_access::readwrite:
|
||||
return KEY_ALL_ACCESS;
|
||||
case key_access::read64:
|
||||
return KEY_READ | KEY_WOW64_64KEY;
|
||||
case key_access::readwrite64:
|
||||
return KEY_ALL_ACCESS | KEY_WOW64_64KEY;
|
||||
}
|
||||
FAIL_FAST();
|
||||
RESULT_NORETURN_RESULT(0);
|
||||
@@ -447,6 +461,7 @@ namespace reg
|
||||
}
|
||||
// including the last null buffer space in the returned buffer-size-bytes
|
||||
// as the registry API we call guarantees null termination
|
||||
// NOLINTNEXTLINE(bugprone-misplaced-widening-cast): size_t and DWORD are effectively the same on x86
|
||||
return static_cast<DWORD>((::wcslen(value) + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
@@ -537,6 +552,7 @@ namespace reg
|
||||
{
|
||||
// including the last null buffer space in the returned buffer-size-bytes
|
||||
// as the registry API we call guarantees null termination
|
||||
// NOLINTNEXTLINE(bugprone-misplaced-widening-cast): size_t and DWORD are effectively the same on x86
|
||||
return static_cast<DWORD>((string.size() + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
@@ -573,6 +589,8 @@ namespace reg
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-exception-escape): Only reduces the size
|
||||
inline size_t trim_buffer(::std::wstring& buffer) WI_NOEXCEPT
|
||||
{
|
||||
// remove any embedded null characters
|
||||
@@ -891,16 +909,16 @@ namespace reg
|
||||
|
||||
// constexpr expressions to determining the get* and set* registry value types
|
||||
// for all supported types T to read/write values
|
||||
template <typename T>
|
||||
template <typename T = void>
|
||||
DWORD get_value_type() WI_NOEXCEPT
|
||||
{
|
||||
static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_type");
|
||||
static_assert(!wistd::is_same_v<T, T>, "Unsupported type for get_value_type");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T = void>
|
||||
DWORD set_value_type() WI_NOEXCEPT
|
||||
{
|
||||
static_assert(sizeof(T) != sizeof(T), "Unsupported type for set_value_type");
|
||||
static_assert(!wistd::is_same_v<T, T>, "Unsupported type for set_value_type");
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -1077,7 +1095,7 @@ namespace reg
|
||||
reg_view_t& operator=(reg_view_t&&) = delete;
|
||||
|
||||
typename err_policy::result open_key(
|
||||
_In_opt_ _In_opt_ PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const
|
||||
_In_opt_ PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const
|
||||
{
|
||||
constexpr DWORD zero_options{0};
|
||||
return err_policy::HResult(
|
||||
@@ -1124,7 +1142,7 @@ namespace reg
|
||||
typename err_policy::result get_value_char_array(
|
||||
_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], DWORD type, _Out_opt_ DwordType* requiredBytes) const
|
||||
{
|
||||
constexpr DwordType zero_value{0ul};
|
||||
constexpr DwordType zero_value{0UL};
|
||||
::wil::assign_to_opt_param(requiredBytes, zero_value);
|
||||
DWORD data_size_bytes{Length * sizeof(WCHAR)};
|
||||
const auto hr = HRESULT_FROM_WIN32(::RegGetValueW(
|
||||
@@ -1306,18 +1324,18 @@ namespace reg
|
||||
constexpr size_t iterator_max_valuename_length = 16383;
|
||||
|
||||
// function overloads to allow *_enumerator objects to be constructed from all 3 types of HKEY representatives
|
||||
inline HKEY get_hkey(HKEY h) WI_NOEXCEPT
|
||||
inline HKEY get_hkey(HKEY key) WI_NOEXCEPT
|
||||
{
|
||||
return h;
|
||||
return key;
|
||||
}
|
||||
inline HKEY get_hkey(const ::wil::unique_hkey& h) WI_NOEXCEPT
|
||||
inline HKEY get_hkey(const ::wil::unique_hkey& key) WI_NOEXCEPT
|
||||
{
|
||||
return h.get();
|
||||
return key.get();
|
||||
}
|
||||
#if defined(__WIL_WINREG_STL)
|
||||
inline HKEY get_hkey(const ::wil::shared_hkey& h) WI_NOEXCEPT
|
||||
inline HKEY get_hkey(const ::wil::shared_hkey& key) WI_NOEXCEPT
|
||||
{
|
||||
return h.get();
|
||||
return key.get();
|
||||
}
|
||||
#endif // #if defined(__WIL_WINREG_STL)
|
||||
|
||||
@@ -1327,7 +1345,7 @@ namespace reg
|
||||
// reference these overload functions
|
||||
inline void clear_name(::std::wstring& name, size_t) WI_NOEXCEPT
|
||||
{
|
||||
name.assign(name.size(), L'\0');
|
||||
std::fill(name.begin(), name.end(), L'\0');
|
||||
}
|
||||
inline ::std::wstring copy_name(const ::std::wstring& str, size_t length) WI_NOEXCEPT
|
||||
{
|
||||
@@ -1442,7 +1460,7 @@ namespace reg
|
||||
class key_iterator_data
|
||||
{
|
||||
public:
|
||||
T name{};
|
||||
T name{}; // NOLINT(misc-non-private-member-variables-in-classes): Part of original interface & cannot change
|
||||
|
||||
key_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key}
|
||||
{
|
||||
@@ -1600,8 +1618,8 @@ namespace reg
|
||||
class value_iterator_data
|
||||
{
|
||||
public:
|
||||
T name{};
|
||||
DWORD type = REG_NONE;
|
||||
T name{}; // NOLINT(misc-non-private-member-variables-in-classes): Part of original interface & cannot change
|
||||
DWORD type = REG_NONE; // NOLINT(misc-non-private-member-variables-in-classes): Part of original interface & cannot change
|
||||
|
||||
value_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{key}
|
||||
{
|
||||
@@ -1711,10 +1729,8 @@ namespace reg
|
||||
|
||||
// resize and try again - growing exponentially up to the max
|
||||
string_length *= 2;
|
||||
if (string_length > ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1)
|
||||
{
|
||||
string_length = ::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1;
|
||||
}
|
||||
string_length = (wistd::min)(
|
||||
string_length, static_cast<DWORD>(::wil::reg::reg_iterator_details::iterator_max_valuename_length + 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1817,16 +1833,8 @@ namespace reg
|
||||
iterator_t& operator+=(size_t offset)
|
||||
{
|
||||
uint32_t newIndex = m_data.m_index + static_cast<uint32_t>(offset);
|
||||
if (newIndex < m_data.m_index)
|
||||
{
|
||||
// fail on integer overflow
|
||||
THROW_HR(E_INVALIDARG);
|
||||
}
|
||||
if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset)
|
||||
{
|
||||
// fail if this creates an end iterator
|
||||
THROW_HR(E_INVALIDARG);
|
||||
}
|
||||
THROW_HR_IF(E_INVALIDARG, newIndex < m_data.m_index); // fail on integer overflow
|
||||
THROW_HR_IF(E_INVALIDARG, newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset); // fail if this creates an end iterator
|
||||
|
||||
// iterate by the integer offset
|
||||
for (size_t count = 0; count < offset; ++count)
|
||||
@@ -1880,14 +1888,9 @@ namespace reg
|
||||
HRESULT move_next() WI_NOEXCEPT
|
||||
{
|
||||
const auto newIndex = m_data.m_index + 1;
|
||||
if (newIndex < m_data.m_index)
|
||||
if ((newIndex < m_data.m_index) || // fail on integer overflow
|
||||
(newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset)) // fail if this creates an end iterator
|
||||
{
|
||||
// fail on integer overflow
|
||||
m_last_error = E_INVALIDARG;
|
||||
}
|
||||
else if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset)
|
||||
{
|
||||
// fail if this creates an end iterator
|
||||
m_last_error = E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
@@ -1956,4 +1959,4 @@ namespace reg
|
||||
|
||||
} // namespace reg
|
||||
} // namespace wil
|
||||
#endif // __WIL_REGISTRY_HELPERS_INCLUDED
|
||||
#endif // __WIL_REGISTRY_HELPERS_INCLUDED
|
||||
|
||||
+800
-158
File diff suppressed because it is too large
Load Diff
Vendored
+10
-7
@@ -32,9 +32,11 @@
|
||||
#error This header is not supported in kernel-mode.
|
||||
#endif
|
||||
|
||||
// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that requests developers verify they want it
|
||||
#pragma warning(push)
|
||||
// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that requests developers verify they want it
|
||||
#pragma warning(disable : 4351)
|
||||
// remove this after fixing - volatile access of '<expression>' is subject to /volatile:<iso|ms> setting; consider using __iso_volatile_load/store intrinsic functions
|
||||
#pragma warning(disable : 4746)
|
||||
|
||||
namespace wil
|
||||
{
|
||||
@@ -107,6 +109,7 @@ namespace details_abi
|
||||
*pointer = nullptr;
|
||||
ULONG_PTR value = 0;
|
||||
__WIL_PRIVATE_RETURN_IF_FAILED(TryGetValue(name, &value));
|
||||
// NOLINTNEXTLINE(performance-no-int-to-ptr): Provenance concealment is intentional here
|
||||
*pointer = reinterpret_cast<void*>(value << 2);
|
||||
return S_OK;
|
||||
}
|
||||
@@ -403,7 +406,7 @@ namespace details_abi
|
||||
T* GetLocal(bool shouldAllocate = false) WI_NOEXCEPT
|
||||
{
|
||||
DWORD const threadId = ::GetCurrentThreadId();
|
||||
size_t const index = (threadId % ARRAYSIZE(m_hashArray));
|
||||
size_t const index = ((threadId >> 2) % ARRAYSIZE(m_hashArray)); // Reduce hash collisions; thread IDs are even.
|
||||
for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext)
|
||||
{
|
||||
if (pNode->threadId == threadId)
|
||||
@@ -435,7 +438,7 @@ namespace details_abi
|
||||
private:
|
||||
struct Node
|
||||
{
|
||||
DWORD threadId = 0xffffffffu;
|
||||
DWORD threadId = 0xffffffffU;
|
||||
Node* pNext = nullptr;
|
||||
T value{};
|
||||
};
|
||||
@@ -518,7 +521,7 @@ namespace details_abi
|
||||
{
|
||||
::ZeroMemory(&info, sizeof(info));
|
||||
|
||||
info.failureId = sequenceId;
|
||||
info.failureId = static_cast<long>(sequenceId);
|
||||
info.hr = hr;
|
||||
info.pszFile = fileName;
|
||||
info.uLineNumber = lineNumber;
|
||||
@@ -666,7 +669,7 @@ namespace details_abi
|
||||
unsigned int minSequenceId,
|
||||
_In_opt_ const DiagnosticsInfo* diagnostics,
|
||||
HRESULT matchRequirement,
|
||||
void* returnAddress)
|
||||
void* returnAddress) const
|
||||
{
|
||||
// First attempt to get the last error and then see if it matches the error returned from
|
||||
// the last caught exception. If it does, then we're good to go and we return that last error.
|
||||
@@ -838,7 +841,7 @@ public:
|
||||
/** Retrieves the origination of the last error that occurred since this class was constructed.
|
||||
The optional parameter allows the failure information returned to be filtered to a specific
|
||||
result. */
|
||||
inline bool GetLastError(FailureInfo& info, HRESULT matchRequirement = S_OK)
|
||||
bool GetLastError(FailureInfo& info, HRESULT matchRequirement = S_OK)
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
@@ -849,7 +852,7 @@ public:
|
||||
|
||||
/** Retrieves the origin of the current exception (within a catch block) since this class was constructed.
|
||||
See @ref GetCaughtExceptionError for more information */
|
||||
inline __declspec(noinline) bool GetCaughtExceptionError(
|
||||
__declspec(noinline) bool GetCaughtExceptionError(
|
||||
_Inout_ wil::FailureInfo& info, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK)
|
||||
{
|
||||
if (m_data)
|
||||
|
||||
+120
-85
@@ -20,8 +20,12 @@
|
||||
#include "common.h"
|
||||
|
||||
#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
|
||||
#ifdef __MINGW32__
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Setup the debug behavior. For kernel-mode, we ignore NDEBUG because that gets set automatically
|
||||
// for driver projects. We mimic the behavior of NT_ASSERT which checks only for DBG.
|
||||
@@ -34,7 +38,11 @@
|
||||
|
||||
/// @cond
|
||||
#if defined(_PREFAST_)
|
||||
#ifdef __cplusplus
|
||||
#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(static_cast<bool>(_exp))
|
||||
#else
|
||||
#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp)
|
||||
#endif
|
||||
#else
|
||||
#ifdef RESULT_DEBUG
|
||||
#define __WI_ANALYSIS_ASSUME(_exp) ((void)0)
|
||||
@@ -248,6 +256,7 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
//*****************************************************************************
|
||||
|
||||
/// @cond
|
||||
// NOLINTBEGIN(bugprone-macro-parentheses): Uses of these macros are tightly controlled
|
||||
#define __R_DIAGNOSTICS(diagnostics) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr
|
||||
#define __R_DIAGNOSTICS_RA(diagnostics, address) \
|
||||
diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr, address
|
||||
@@ -319,11 +328,14 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
#define __R_INFO_ONLY(CODE) \
|
||||
__R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \
|
||||
__R_IF_LINE(__R_LINE_VALUE) \
|
||||
__R_IF_FILE(__R_COMMA __R_FILE_VALUE) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE)
|
||||
__R_IF_FILE(__R_COMMA __R_FILE_VALUE) \
|
||||
__R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) // NOLINT(bugprone-lambda-function-name)
|
||||
#define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA
|
||||
#define __R_INFO_NOFILE_ONLY(CODE) \
|
||||
__R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \
|
||||
__R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE)
|
||||
__R_IF_LINE(__R_LINE_VALUE) \
|
||||
__R_IF_FILE(__R_COMMA "wil") \
|
||||
__R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) // NOLINT(bugprone-lambda-function-name)
|
||||
#define __R_INFO_NOFILE(CODE) __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA
|
||||
#define __R_FN_PARAMS_ONLY \
|
||||
__R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) \
|
||||
@@ -361,8 +373,13 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
template <unsigned int optimizerCounter> \
|
||||
inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
||||
#else
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
#define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
||||
#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
||||
#else
|
||||
#define __R_DIRECT_METHOD(RetType, MethodName) inline RetType MethodName
|
||||
#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline RetType MethodName
|
||||
#endif
|
||||
#endif
|
||||
#define __R_DIRECT_FN_PARAMS __R_FN_PARAMS
|
||||
#define __R_DIRECT_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY
|
||||
@@ -517,12 +534,14 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
#define __RFF_INFO_ONLY(CODE) \
|
||||
__RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \
|
||||
__RFF_IF_LINE(__R_LINE_VALUE) \
|
||||
__RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE)
|
||||
__RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) \
|
||||
__RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) // NOLINT(bugprone-lambda-function-name)
|
||||
#define __RFF_INFO(CODE) __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA
|
||||
#define __RFF_INFO_NOFILE_ONLY(CODE) \
|
||||
__RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \
|
||||
__RFF_IF_LINE(__R_LINE_VALUE) \
|
||||
__RFF_IF_FILE(__RFF_COMMA "wil") __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE)
|
||||
__RFF_IF_FILE(__RFF_COMMA "wil") \
|
||||
__RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) // NOLINT(bugprone-lambda-function-name)
|
||||
#define __RFF_INFO_NOFILE(CODE) __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA
|
||||
#define __RFF_FN_PARAMS_ONLY \
|
||||
__RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) \
|
||||
@@ -811,6 +830,7 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \
|
||||
} \
|
||||
__WI_SUPPRESS_BREAKING_WARNINGS_E while ((void)0, 0)
|
||||
// NOLINTEND(bugprone-macro-parentheses)
|
||||
/// @endcond
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -1127,19 +1147,19 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
// Always logs a known failure
|
||||
#define LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define LOG_LAST_ERROR() __R_FN(Log_GetLastError)(__R_INFO_ONLY(nullptr))
|
||||
#define LOG_WIN32(win32err) __R_FN(Log_Win32)(__R_INFO(#win32err) win32err)
|
||||
#define LOG_NTSTATUS(status) __R_FN(Log_NtStatus)(__R_INFO(#status) status)
|
||||
#define LOG_WIN32(win32err) __R_FN(Log_Win32)(__R_INFO(#win32err)(win32err))
|
||||
#define LOG_NTSTATUS(status) __R_FN(Log_NtStatus)(__R_INFO(#status)(status))
|
||||
|
||||
// Conditionally logs failures - returns parameter value
|
||||
#define LOG_IF_FAILED(hr) __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
|
||||
#define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err)
|
||||
#define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr)
|
||||
#define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err)(win32err))
|
||||
#define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr)(ptr))
|
||||
#define LOG_HR_IF(hr, condition) __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
|
||||
#define LOG_HR_IF_NULL(hr, ptr) __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr)
|
||||
#define LOG_LAST_ERROR_IF(condition) __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition))
|
||||
#define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr)
|
||||
#define LOG_IF_NTSTATUS_FAILED(status) __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status) status)
|
||||
#define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr)(ptr))
|
||||
#define LOG_IF_NTSTATUS_FAILED(status) __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status)(status))
|
||||
|
||||
// Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures
|
||||
#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr))
|
||||
@@ -1197,21 +1217,21 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
// Always fail fast a known failure
|
||||
#define FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define FAIL_FAST_LAST_ERROR() __RFF_FN(FailFast_GetLastError)(__RFF_INFO_ONLY(nullptr))
|
||||
#define FAIL_FAST_WIN32(win32err) __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err) win32err)
|
||||
#define FAIL_FAST_NTSTATUS(status) __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status) status)
|
||||
#define FAIL_FAST_WIN32(win32err) __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err)(win32err))
|
||||
#define FAIL_FAST_NTSTATUS(status) __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status)(status))
|
||||
|
||||
// Conditionally fail fast failures - returns parameter value
|
||||
#define FAIL_FAST_IF_FAILED(hr) __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) \
|
||||
__RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
|
||||
#define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err)
|
||||
#define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr)
|
||||
#define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err)(win32err))
|
||||
#define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr)(ptr))
|
||||
#define FAIL_FAST_HR_IF(hr, condition) \
|
||||
__RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
|
||||
#define FAIL_FAST_HR_IF_NULL(hr, ptr) __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr)
|
||||
#define FAIL_FAST_LAST_ERROR_IF(condition) __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition))
|
||||
#define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr)
|
||||
#define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status)
|
||||
#define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr)(ptr))
|
||||
#define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status)(status))
|
||||
|
||||
// Always fail fast a known failure - fail fast a var-arg message on failure
|
||||
#define FAIL_FAST_HR_MSG(hr, fmt, ...) \
|
||||
@@ -1253,7 +1273,7 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
|
||||
// Conditionally fail fast failures - returns parameter value
|
||||
#define FAIL_FAST_IF(condition) __RFF_FN(FailFast_If)(__RFF_INFO(#condition) wil::verify_bool(condition))
|
||||
#define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr)
|
||||
#define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr)(ptr))
|
||||
|
||||
// Always fail fast a known failure - fail fast a var-arg message on failure
|
||||
#define FAIL_FAST_MSG(fmt, ...) __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
||||
@@ -1312,22 +1332,22 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
// Always throw a known failure
|
||||
#define THROW_HR(hr) __R_FN(Throw_Hr)(__R_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define THROW_LAST_ERROR() __R_FN(Throw_GetLastError)(__R_INFO_ONLY(nullptr))
|
||||
#define THROW_WIN32(win32err) __R_FN(Throw_Win32)(__R_INFO(#win32err) win32err)
|
||||
#define THROW_EXCEPTION(exception) wil::details::ReportFailure_CustomException(__R_INFO(#exception) exception)
|
||||
#define THROW_NTSTATUS(status) __R_FN(Throw_NtStatus)(__R_INFO(#status) status)
|
||||
#define THROW_WIN32(win32err) __R_FN(Throw_Win32)(__R_INFO(#win32err)(win32err))
|
||||
#define THROW_EXCEPTION(exception) wil::details::ReportFailure_CustomException(__R_INFO(#exception)(exception))
|
||||
#define THROW_NTSTATUS(status) __R_FN(Throw_NtStatus)(__R_INFO(#status)(status))
|
||||
|
||||
// Conditionally throw failures - returns parameter value
|
||||
#define THROW_IF_FAILED(hr) __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr))
|
||||
#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
|
||||
#define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err)
|
||||
#define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr)
|
||||
#define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err)(win32err))
|
||||
#define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr)(ptr))
|
||||
#define THROW_HR_IF(hr, condition) __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
|
||||
#define THROW_HR_IF_NULL(hr, ptr) __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr)
|
||||
#define THROW_WIN32_IF(win32err, condition) \
|
||||
__R_FN(Throw_Win32If)(__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition))
|
||||
#define THROW_LAST_ERROR_IF(condition) __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition))
|
||||
#define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr)
|
||||
#define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status)
|
||||
#define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr)(ptr))
|
||||
#define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status)(status))
|
||||
|
||||
// Always throw a known failure - throw a var-arg message on failure
|
||||
#define THROW_HR_MSG(hr, fmt, ...) \
|
||||
@@ -1410,9 +1430,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
#define CATCH_LOG_RETURN() \
|
||||
catch (...) \
|
||||
{ \
|
||||
__pragma(warning(suppress : 4297)); \
|
||||
LOG_CAUGHT_EXCEPTION(); \
|
||||
return; \
|
||||
__pragma(warning(push)) __pragma(warning(disable : 4297)) LOG_CAUGHT_EXCEPTION(); \
|
||||
__pragma(warning(pop)) return; \
|
||||
}
|
||||
#define CATCH_LOG_MSG(fmt, ...) \
|
||||
catch (...) \
|
||||
@@ -1423,9 +1442,8 @@ WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
||||
#define CATCH_LOG_RETURN_MSG(fmt, ...) \
|
||||
catch (...) \
|
||||
{ \
|
||||
__pragma(warning(suppress : 4297)); \
|
||||
LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
||||
return; \
|
||||
__pragma(warning(push)) __pragma(warning(disable : 4297)) LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
||||
__pragma(warning(pop)) return; \
|
||||
}
|
||||
#define CATCH_FAIL_FAST() \
|
||||
catch (...) \
|
||||
@@ -1794,7 +1812,7 @@ inline HRESULT GetFailureLogString(
|
||||
// it for OutputDebugString or exception message, then generate the default string.
|
||||
if (pszDest[0] == L'\0')
|
||||
{
|
||||
PCSTR pszType = "";
|
||||
PCSTR pszType = ""; // NOLINT(clang-analyzer-deadcode.DeadStores): Good hygiene
|
||||
switch (failure.type)
|
||||
{
|
||||
case FailureType::Exception:
|
||||
@@ -1897,6 +1915,7 @@ inline HRESULT GetFailureLogString(
|
||||
{
|
||||
dest = details::LogStringPrintf(dest, destEnd, L"\n");
|
||||
}
|
||||
(void)dest; // Most recent stores are for consistency and debugging
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2065,7 +2084,10 @@ namespace details
|
||||
template <typename TFunctor>
|
||||
struct functor_wrapper_void : public IFunctor
|
||||
{
|
||||
private:
|
||||
TFunctor&& functor;
|
||||
|
||||
public:
|
||||
functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward<TFunctor>(functor_))
|
||||
{
|
||||
}
|
||||
@@ -2082,7 +2104,10 @@ namespace details
|
||||
template <typename TFunctor>
|
||||
struct functor_wrapper_HRESULT : public IFunctor
|
||||
{
|
||||
private:
|
||||
TFunctor&& functor;
|
||||
|
||||
public:
|
||||
functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward<TFunctor>(functor_))
|
||||
{
|
||||
}
|
||||
@@ -2095,8 +2120,11 @@ namespace details
|
||||
template <typename TFunctor, typename TReturn>
|
||||
struct functor_wrapper_other : public IFunctor
|
||||
{
|
||||
private:
|
||||
TFunctor&& functor;
|
||||
TReturn& retVal;
|
||||
|
||||
public:
|
||||
functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward<TFunctor>(functor_)), retVal(retval_)
|
||||
{
|
||||
}
|
||||
@@ -2179,7 +2207,7 @@ namespace details
|
||||
__RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT;
|
||||
} // namespace __RFF_NS_NAME
|
||||
|
||||
RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& info);
|
||||
RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& failure);
|
||||
inline void LogFailure(
|
||||
__R_FN_PARAMS_FULL,
|
||||
FailureType type,
|
||||
@@ -2504,7 +2532,7 @@ namespace details
|
||||
{
|
||||
}
|
||||
|
||||
template <typename param_t>
|
||||
template <typename param_t> // NOLINTNEXTLINE(bugprone-forwarding-reference-overload): Internal type
|
||||
RefAndObject(param_t&& param1) : m_refCount(1), m_object(wistd::forward<param_t>(param1))
|
||||
{
|
||||
}
|
||||
@@ -2555,13 +2583,13 @@ namespace details
|
||||
}
|
||||
__WI_POP_WARNINGS
|
||||
|
||||
inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags)
|
||||
inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD exr, _In_opt_ PCONTEXT ctxt, _In_ DWORD flags)
|
||||
{
|
||||
// if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.)
|
||||
// or via direct linkage (e.g. UWP apps), then use it.
|
||||
if (g_pfnRaiseFailFastException)
|
||||
{
|
||||
g_pfnRaiseFailFastException(er, cr, flags);
|
||||
g_pfnRaiseFailFastException(exr, ctxt, flags);
|
||||
}
|
||||
// if not, as a best effort, we are just going to call the intrinsic.
|
||||
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
||||
@@ -2624,7 +2652,7 @@ namespace details
|
||||
::DebugBreak();
|
||||
}
|
||||
|
||||
inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags)
|
||||
inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD exr, _In_ PCONTEXT ctxt, _In_ DWORD flags)
|
||||
{
|
||||
auto k32handle = GetModuleHandleW(L"kernelbase.dll");
|
||||
_Analysis_assume_(k32handle != nullptr);
|
||||
@@ -2632,7 +2660,7 @@ namespace details
|
||||
details::GetProcAddress<decltype(WilDynamicLoadRaiseFailFastException)*>(k32handle, "RaiseFailFastException");
|
||||
if (pfnRaiseFailFastException)
|
||||
{
|
||||
pfnRaiseFailFastException(er, cr, flags);
|
||||
pfnRaiseFailFastException(exr, ctxt, flags);
|
||||
}
|
||||
}
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
@@ -2688,24 +2716,24 @@ namespace details
|
||||
__declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT hr) WI_NOEXCEPT
|
||||
{
|
||||
// Constants taken from ntstatus.h
|
||||
static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = 0xC000000D;
|
||||
static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = 0xC00000E5;
|
||||
static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = 0xC0000095;
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A;
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
|
||||
static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = 0xC0000002;
|
||||
static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = 0x80000005;
|
||||
static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B;
|
||||
static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = 0xC0000273;
|
||||
static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = 0xC0000161;
|
||||
static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = 0xC0000163;
|
||||
static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = 0xC0000023;
|
||||
static constexpr NTSTATUS WIL_STATUS_DISK_FULL = 0xC000007F;
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = 0xC0000033;
|
||||
static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = 0xC0000135;
|
||||
static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = 0xC0000059;
|
||||
static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = 0xC000A083;
|
||||
static constexpr HRESULT WIL_E_FAIL = 0x80004005;
|
||||
static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = static_cast<NTSTATUS>(0xC000000D);
|
||||
static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = static_cast<NTSTATUS>(0xC00000E5);
|
||||
static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = static_cast<NTSTATUS>(0xC0000095);
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = static_cast<NTSTATUS>(0xC000003A);
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = static_cast<NTSTATUS>(0xC0000034);
|
||||
static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = static_cast<NTSTATUS>(0xC0000002);
|
||||
static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = static_cast<NTSTATUS>(0x80000005);
|
||||
static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = static_cast<NTSTATUS>(0xC000042B);
|
||||
static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = static_cast<NTSTATUS>(0xC0000273);
|
||||
static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = static_cast<NTSTATUS>(0xC0000161);
|
||||
static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = static_cast<NTSTATUS>(0xC0000163);
|
||||
static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = static_cast<NTSTATUS>(0xC0000023);
|
||||
static constexpr NTSTATUS WIL_STATUS_DISK_FULL = static_cast<NTSTATUS>(0xC000007F);
|
||||
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = static_cast<NTSTATUS>(0xC0000033);
|
||||
static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = static_cast<NTSTATUS>(0xC0000135);
|
||||
static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = static_cast<NTSTATUS>(0xC0000059);
|
||||
static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = static_cast<NTSTATUS>(0xC000A083);
|
||||
static constexpr HRESULT WIL_E_FAIL = static_cast<HRESULT>(0x80004005);
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
@@ -3030,7 +3058,7 @@ namespace details
|
||||
_Pre_satisfies_(pStart <= pEnd) _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_) _When_(
|
||||
(pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0),
|
||||
_Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) unsigned char* pStart,
|
||||
_Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd,
|
||||
_Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, // NOLINT(readability-non-const-parameter): For consistency with pStart
|
||||
_In_opt_z_ TString pszString,
|
||||
_Outptr_result_maybenull_z_ TString* ppszBufferString)
|
||||
{
|
||||
@@ -3409,7 +3437,7 @@ public:
|
||||
|
||||
// Relies upon generated copy constructor and assignment operator
|
||||
|
||||
protected:
|
||||
private:
|
||||
FailureInfo m_failureInfo;
|
||||
details::shared_buffer m_spStrings;
|
||||
};
|
||||
@@ -3464,7 +3492,7 @@ public:
|
||||
}
|
||||
|
||||
//! Provides a string representing the FailureInfo from this exception.
|
||||
WI_NODISCARD inline const char* __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override
|
||||
WI_NODISCARD const char* __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override
|
||||
{
|
||||
#if !defined(NONLS) && !defined(NOAPISET)
|
||||
if (!m_what)
|
||||
@@ -3498,16 +3526,18 @@ public:
|
||||
|
||||
// Relies upon auto-generated copy constructor and assignment operator
|
||||
protected:
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes): Historically part of API and too risky to change
|
||||
StoredFailureInfo m_failure; //!< The failure information for this exception
|
||||
mutable details::shared_buffer m_what; //!< The on-demand generated what() string
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
//! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types).
|
||||
static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT
|
||||
{
|
||||
FailureInfo fi = {};
|
||||
fi.type = FailureType::Exception;
|
||||
fi.hr = hr;
|
||||
return fi;
|
||||
FailureInfo info = {};
|
||||
info.type = FailureType::Exception;
|
||||
info.hr = hr;
|
||||
return info;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -4112,15 +4142,19 @@ namespace details
|
||||
inline HRESULT ResultFromExceptionSeh(
|
||||
const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__try
|
||||
#endif
|
||||
{
|
||||
return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor);
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
__except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH)
|
||||
{
|
||||
WI_ASSERT(false);
|
||||
RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
|
||||
@@ -4517,28 +4551,29 @@ namespace details
|
||||
}
|
||||
|
||||
// parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT)
|
||||
EXCEPTION_RECORD er{};
|
||||
er.NumberParameters = 1; // default to be safe, see below
|
||||
er.ExceptionCode = static_cast<DWORD>(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409
|
||||
er.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
er.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w
|
||||
EXCEPTION_RECORD exr{};
|
||||
exr.NumberParameters = 1; // default to be safe, see below
|
||||
// NOLINTNEXTLINE(readability-redundant-casting): STATUS_ macros inconsistently defined in Windows headers
|
||||
exr.ExceptionCode = static_cast<DWORD>(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409
|
||||
exr.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||||
exr.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w
|
||||
if (failure.returnAddress == nullptr) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it
|
||||
{
|
||||
// passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing
|
||||
// !analyze functionality to crawl the stack looking for the HRESULT
|
||||
// don't pass a 0 HRESULT in param 1 because that will result in worse bucketing.
|
||||
WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
|
||||
WilRaiseFailFastException(&exr, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
|
||||
}
|
||||
else // use FailureInfo caller address
|
||||
{
|
||||
// parameter 1 is the failing HRESULT
|
||||
// parameter 2 is the line number. This is never used for bucketing (due to code churn causing re-bucketing) but is available in the dump's
|
||||
// exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps.
|
||||
er.NumberParameters = 3;
|
||||
er.ExceptionInformation[1] = failure.hr;
|
||||
er.ExceptionInformation[2] = failure.uLineNumber;
|
||||
er.ExceptionAddress = failure.returnAddress;
|
||||
WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */);
|
||||
exr.NumberParameters = 3;
|
||||
exr.ExceptionInformation[1] = failure.hr;
|
||||
exr.ExceptionInformation[2] = failure.uLineNumber;
|
||||
exr.ExceptionAddress = failure.returnAddress;
|
||||
WilRaiseFailFastException(&exr, nullptr, 0 /* do not generate exception address */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4609,7 +4644,7 @@ namespace details
|
||||
__WI_SUPPRESS_BREAKING_WARNINGS_S
|
||||
if ((T == FailureType::FailFast) || WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast))
|
||||
{
|
||||
WilFailFast(const_cast<FailureInfo&>(failure));
|
||||
WilFailFast(failure);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4626,7 +4661,7 @@ namespace details
|
||||
ThrowResultException(failure);
|
||||
|
||||
// Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup)
|
||||
WilFailFast(const_cast<FailureInfo&>(failure));
|
||||
WilFailFast(failure);
|
||||
}
|
||||
__WI_SUPPRESS_BREAKING_WARNINGS_E
|
||||
}
|
||||
@@ -5185,7 +5220,7 @@ namespace details
|
||||
|
||||
inline void SetFailureInfo(_In_ FailureInfo const& failure, _Inout_ ResultException& exception) WI_NOEXCEPT
|
||||
{
|
||||
return exception.SetFailureInfo(failure);
|
||||
exception.SetFailureInfo(failure);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -7226,10 +7261,10 @@ struct err_returncode_policy
|
||||
RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn);
|
||||
return S_OK;
|
||||
}
|
||||
__forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
||||
__forceinline static HRESULT Win32Handle(HANDLE handleIn, _Out_ HANDLE* handleOut)
|
||||
{
|
||||
*ph = h;
|
||||
RETURN_LAST_ERROR_IF_NULL_EXPECTED(h);
|
||||
*handleOut = handleIn;
|
||||
RETURN_LAST_ERROR_IF_NULL_EXPECTED(handleIn);
|
||||
return S_OK;
|
||||
}
|
||||
_Post_satisfies_(return == hr) __forceinline static HRESULT HResult(HRESULT hr)
|
||||
@@ -7259,10 +7294,10 @@ struct err_failfast_policy
|
||||
{
|
||||
FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn);
|
||||
}
|
||||
__forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
||||
__forceinline static result Win32Handle(HANDLE handleIn, _Out_ HANDLE* handleOut)
|
||||
{
|
||||
*ph = h;
|
||||
FAIL_FAST_LAST_ERROR_IF_NULL(h);
|
||||
*handleOut = handleIn;
|
||||
FAIL_FAST_LAST_ERROR_IF_NULL(handleIn);
|
||||
}
|
||||
_When_(FAILED(hr), _Analysis_noreturn_)
|
||||
__forceinline static result HResult(HRESULT hr)
|
||||
@@ -7294,10 +7329,10 @@ struct err_exception_policy
|
||||
{
|
||||
THROW_IF_WIN32_BOOL_FALSE(fReturn);
|
||||
}
|
||||
__forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
||||
__forceinline static result Win32Handle(HANDLE handleIn, _Out_ HANDLE* handleOut)
|
||||
{
|
||||
*ph = h;
|
||||
THROW_LAST_ERROR_IF_NULL(h);
|
||||
*handleOut = handleIn;
|
||||
THROW_LAST_ERROR_IF_NULL(handleIn);
|
||||
}
|
||||
_When_(FAILED(hr), _Analysis_noreturn_)
|
||||
__forceinline static result HResult(HRESULT hr)
|
||||
|
||||
@@ -121,11 +121,13 @@ namespace details
|
||||
/// @endcond
|
||||
} // namespace wil
|
||||
|
||||
#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS
|
||||
// Automatically call RoOriginateError upon error origination by including this file
|
||||
WI_HEADER_INITIALIZATION_FUNCTION(ResultStowedExceptionInitialize, [] {
|
||||
::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions);
|
||||
::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback);
|
||||
return 1;
|
||||
})
|
||||
#endif // RESULT_SUPPRESS_STATIC_INITIALIZERS
|
||||
|
||||
#endif // __WIL_RESULT_ORIGINATE_INCLUDED
|
||||
|
||||
Vendored
+98
-2
@@ -133,6 +133,7 @@ inline PCWSTR str_raw_ptr(const std::wstring& 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.
|
||||
@@ -145,6 +146,26 @@ class basic_zstring_view : public std::basic_string_view<TChar>
|
||||
{
|
||||
using size_type = typename std::basic_string_view<TChar>::size_type;
|
||||
|
||||
template <typename T>
|
||||
struct has_c_str
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(std::declval<U>().c_str(), std::true_type());
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_size
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(std::declval<U>().size() == 1, std::true_type());
|
||||
template <typename U>
|
||||
static std::false_type test(...);
|
||||
static constexpr bool value = decltype(test<T>(0))::value;
|
||||
};
|
||||
|
||||
public:
|
||||
constexpr basic_zstring_view() noexcept = default;
|
||||
constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default;
|
||||
@@ -177,6 +198,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
template <typename TSrc, std::enable_if_t<has_c_str<TSrc>::value && has_size<TSrc>::value && std::is_same_v<typename TSrc::value_type, TChar>>* = nullptr>
|
||||
constexpr basic_zstring_view(TSrc const& src) noexcept : std::basic_string_view<TChar>(src.c_str(), src.size())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename TSrc, std::enable_if_t<has_c_str<TSrc>::value && !has_size<TSrc>::value && std::is_same_v<typename TSrc::value_type, TChar>>* = nullptr>
|
||||
constexpr basic_zstring_view(TSrc const& src) noexcept : std::basic_string_view<TChar>(src.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
@@ -211,23 +242,88 @@ private:
|
||||
using zstring_view = basic_zstring_view<char>;
|
||||
using zwstring_view = basic_zstring_view<wchar_t>;
|
||||
|
||||
// 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.
|
||||
template <typename TChar>
|
||||
inline auto str_raw_ptr(basic_zstring_view<TChar> str)
|
||||
{
|
||||
return str.c_str();
|
||||
}
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
constexpr zstring_view operator""_zv(const char* str, std::size_t len) noexcept
|
||||
{
|
||||
return zstring_view(str, len);
|
||||
return {str, len};
|
||||
}
|
||||
|
||||
constexpr zwstring_view operator""_zv(const wchar_t* str, std::size_t len) noexcept
|
||||
{
|
||||
return zwstring_view(str, len);
|
||||
return {str, len};
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
#endif // __cpp_lib_string_view >= 201606L
|
||||
|
||||
#if __WI_LIBCPP_STD_VER >= 17
|
||||
// This is a helper that allows one to construct a functor that has an overloaded operator()
|
||||
// composed from the operator()s of multiple lambdas. It is most useful as the "visitor" for a
|
||||
// std::visit call on a std::variant. A lambda for each type in the variant, and optionally one
|
||||
// generic lambda, can be provided to perform compile time visitation of the std::variant.
|
||||
//
|
||||
// Example:
|
||||
// std::variant<int, bool, double, void*> theVariant;
|
||||
// std::visit(wil::overloaded{
|
||||
// [](int theInt)
|
||||
// {
|
||||
// // Handle int.
|
||||
// },
|
||||
// [](double theDouble)
|
||||
// {
|
||||
// // Handle double.
|
||||
// },
|
||||
// [](auto boolOrVoidPtr)
|
||||
// {
|
||||
// // This will receive all the remaining types. Alternatively, handle each type with
|
||||
// // a lambda that accepts that type. If all types are not handled, you get a
|
||||
// // compile-time error, which makes std::visit superior to an if-else ladder that
|
||||
// // tries to handle each type in the variant.
|
||||
// }},
|
||||
// theVariant);
|
||||
//
|
||||
template <typename... T>
|
||||
struct overloaded final : T...
|
||||
{
|
||||
using T::operator()...;
|
||||
|
||||
// This allows one to use the () syntax to construct the visitor, instead of {}. Both are
|
||||
// equivalent, and the choice ultimately boils down to preference of style.
|
||||
template <typename... Fs>
|
||||
constexpr explicit overloaded(Fs&&... fs) : T{std::forward<Fs>(fs)}...
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Deduction guide to aid CTAD.
|
||||
template <typename... T>
|
||||
overloaded(T...) -> overloaded<T...>;
|
||||
|
||||
#endif // __WI_LIBCPP_STD_VER >= 17
|
||||
|
||||
} // namespace wil
|
||||
|
||||
// This suppression is a temporary workaround to allow libraries built with C++20 to link into binaries built with
|
||||
// earlier standard versions such as C++17. This appears to be an issue even when this specialization goes unused
|
||||
#ifndef WIL_SUPPRESS_STD_FORMAT_USE
|
||||
#if (__WI_LIBCPP_STD_VER >= 20) && WI_HAS_INCLUDE(<format>, 1) // Assume present if C++20
|
||||
#include <format>
|
||||
template <typename TChar>
|
||||
struct std::formatter<wil::basic_zstring_view<TChar>, TChar> : std::formatter<std::basic_string_view<TChar>, TChar>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
#endif // __WIL_STL_INCLUDED
|
||||
|
||||
+187
-80
@@ -38,10 +38,10 @@
|
||||
#endif
|
||||
|
||||
/// @cond
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
#if WIL_USE_STL && (__cpp_lib_bit_cast >= 201806L)
|
||||
#define __WI_CONSTEXPR_BIT_CAST constexpr
|
||||
#else
|
||||
#define __WI_CONSTEXPR_BIT_CAST inline
|
||||
#define __WI_CONSTEXPR_BIT_CAST // All uses are templates, which is implicitly inline
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
@@ -130,9 +130,9 @@ struct weak_ordering
|
||||
signed char m_value;
|
||||
};
|
||||
|
||||
inline constexpr weak_ordering weak_ordering::less{static_cast<signed char>(-1)};
|
||||
inline constexpr weak_ordering weak_ordering::equivalent{static_cast<signed char>(0)};
|
||||
inline constexpr weak_ordering weak_ordering::greater{static_cast<signed char>(1)};
|
||||
__WI_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::less{static_cast<signed char>(-1)};
|
||||
__WI_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::equivalent{static_cast<signed char>(0)};
|
||||
__WI_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::greater{static_cast<signed char>(1)};
|
||||
|
||||
#endif
|
||||
} // namespace wistd
|
||||
@@ -207,43 +207,56 @@ namespace filetime_duration
|
||||
|
||||
namespace filetime
|
||||
{
|
||||
constexpr unsigned long long to_int64(const FILETIME& ft) WI_NOEXCEPT
|
||||
template <typename Int64 = unsigned long long, wistd::enable_if_t<wistd::is_integral_v<Int64> && (sizeof(Int64) == sizeof(FILETIME)), int> = 0>
|
||||
constexpr Int64 to_int64(const FILETIME& val) WI_NOEXCEPT
|
||||
{
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
return std::bit_cast<unsigned long long>(ft);
|
||||
#if WIL_USE_STL && (__cpp_lib_bit_cast >= 201806L)
|
||||
return std::bit_cast<Int64>(val);
|
||||
#else
|
||||
// Cannot reinterpret_cast FILETIME* to unsigned long long*
|
||||
// due to alignment differences.
|
||||
return (static_cast<unsigned long long>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
// Cannot reinterpret_cast FILETIME* to Int64* due to alignment differences.
|
||||
return (static_cast<Int64>(val.dwHighDateTime) << 32) + val.dwLowDateTime;
|
||||
#endif
|
||||
}
|
||||
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME from_int64(unsigned long long i64) WI_NOEXCEPT
|
||||
namespace details
|
||||
{
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
template <typename Int>
|
||||
using select_int64 =
|
||||
wistd::conditional_t<sizeof(Int) == 8, Int, wistd::conditional_t<wistd::is_signed_v<Int>, long long, unsigned long long>>;
|
||||
}
|
||||
|
||||
template <typename Int, wistd::enable_if_t<wistd::is_integral_v<Int> && (sizeof(Int) <= sizeof(FILETIME)), int> = 0>
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME from_int64(Int val) WI_NOEXCEPT
|
||||
{
|
||||
using Int64 = details::select_int64<Int>;
|
||||
auto i64 = static_cast<Int64>(val);
|
||||
|
||||
#if WIL_USE_STL && (__cpp_lib_bit_cast >= 201806L)
|
||||
return std::bit_cast<FILETIME>(i64);
|
||||
#else
|
||||
static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match");
|
||||
static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), "alignment not compatible with type pun");
|
||||
static_assert(__alignof(Int64) >= __alignof(FILETIME), "alignment not compatible with type pun");
|
||||
return *reinterpret_cast<FILETIME*>(&i64);
|
||||
#endif
|
||||
}
|
||||
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME add(_In_ FILETIME const& ft, long long delta100ns) WI_NOEXCEPT
|
||||
template <typename Int, wistd::enable_if_t<wistd::is_integral_v<Int> && (sizeof(Int) <= sizeof(FILETIME)), int> = 0>
|
||||
__WI_CONSTEXPR_BIT_CAST FILETIME add(FILETIME const& baseTime, Int delta100ns) WI_NOEXCEPT
|
||||
{
|
||||
return from_int64(to_int64(ft) + delta100ns);
|
||||
using Int64 = details::select_int64<Int>;
|
||||
return from_int64(to_int64<Int64>(baseTime) + delta100ns);
|
||||
}
|
||||
|
||||
constexpr bool is_empty(const FILETIME& ft) WI_NOEXCEPT
|
||||
constexpr bool is_empty(const FILETIME& val) WI_NOEXCEPT
|
||||
{
|
||||
return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0);
|
||||
return (val.dwHighDateTime == 0) && (val.dwLowDateTime == 0);
|
||||
}
|
||||
|
||||
inline FILETIME get_system_time() WI_NOEXCEPT
|
||||
{
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return ft;
|
||||
FILETIME now;
|
||||
GetSystemTimeAsFileTime(&now);
|
||||
return now;
|
||||
}
|
||||
|
||||
/// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated.
|
||||
@@ -340,7 +353,7 @@ constexpr rect_type rect_from_size(length_type x, length_type y, length_type wid
|
||||
// Adjust stackBufferLength based on typical result sizes to optimize use and
|
||||
// to test the boundary cases.
|
||||
template <typename string_type, size_t stackBufferLength = 256>
|
||||
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function<HRESULT(PWSTR, size_t, size_t*)> callback) WI_NOEXCEPT
|
||||
HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, const wistd::function<HRESULT(PWSTR, size_t, size_t*)>& callback) WI_NOEXCEPT
|
||||
{
|
||||
details::string_maker<string_type> maker;
|
||||
|
||||
@@ -651,36 +664,72 @@ string_type QueryFullProcessImageNameW(HANDLE processHandle = GetCurrentProcess(
|
||||
THROW_IF_FAILED((wil::QueryFullProcessImageNameW<string_type, stackBufferLength>(processHandle, flags, result)));
|
||||
return result;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
|
||||
// Lookup a DWORD value under HKLM\...\Image File Execution Options\<current process name>
|
||||
namespace details
|
||||
{
|
||||
// Lookup a DWORD value under HKLM\...\Image File Execution Options\<current process name>
|
||||
inline HRESULT GetCurrentProcessExecutionOptionNoThrow(PCWSTR valueName, DWORD defaultValue, DWORD* result)
|
||||
{
|
||||
*result = defaultValue;
|
||||
|
||||
wil::unique_cotaskmem_string filePath;
|
||||
RETURN_IF_FAILED(wil::GetModuleFileNameW<wil::unique_cotaskmem_string>(nullptr, filePath));
|
||||
if (auto lastSlash = wcsrchr(filePath.get(), L'\\'))
|
||||
{
|
||||
const auto fileName = lastSlash + 1;
|
||||
wil::unique_cotaskmem_string keyPath;
|
||||
RETURN_IF_FAILED(wil::str_concat_nothrow<wil::unique_cotaskmem_string>(
|
||||
keyPath, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)", fileName));
|
||||
DWORD value{};
|
||||
DWORD sizeofValue = sizeof(value);
|
||||
if (::RegGetValueW(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
keyPath.get(),
|
||||
valueName,
|
||||
#ifdef RRF_SUBKEY_WOW6464KEY
|
||||
RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,
|
||||
#else
|
||||
RRF_RT_REG_DWORD,
|
||||
#endif
|
||||
nullptr,
|
||||
&value,
|
||||
&sizeofValue) == ERROR_SUCCESS)
|
||||
{
|
||||
*result = value;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultValue = 0)
|
||||
{
|
||||
auto filePath = wil::GetModuleFileNameW<wil::unique_cotaskmem_string>();
|
||||
if (auto lastSlash = wcsrchr(filePath.get(), L'\\'))
|
||||
DWORD result{};
|
||||
THROW_IF_FAILED(details::GetCurrentProcessExecutionOptionNoThrow(valueName, defaultValue, &result));
|
||||
return result;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
// No easy return mechanism for err_returncode_policy so skipping it.
|
||||
inline DWORD GetCurrentProcessExecutionOptionNoThrow(PCWSTR valueName, DWORD defaultValue = 0)
|
||||
{
|
||||
DWORD result{};
|
||||
if (FAILED(details::GetCurrentProcessExecutionOptionNoThrow(valueName, defaultValue, &result)))
|
||||
{
|
||||
const auto fileName = lastSlash + 1;
|
||||
auto keyPath = wil::str_concat<wil::unique_cotaskmem_string>(
|
||||
LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)", fileName);
|
||||
DWORD value{}, sizeofValue = sizeof(value);
|
||||
if (::RegGetValueW(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
keyPath.get(),
|
||||
valueName,
|
||||
#ifdef RRF_SUBKEY_WOW6464KEY
|
||||
RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY,
|
||||
#else
|
||||
RRF_RT_REG_DWORD,
|
||||
#endif
|
||||
nullptr,
|
||||
&value,
|
||||
&sizeofValue) == ERROR_SUCCESS)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
return defaultValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline DWORD GetCurrentProcessExecutionOptionFailFast(PCWSTR valueName, DWORD defaultValue = 0)
|
||||
{
|
||||
DWORD result{};
|
||||
FAIL_FAST_IF_FAILED(details::GetCurrentProcessExecutionOptionNoThrow(valueName, defaultValue, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef DebugBreak // Some code defines 'DebugBreak' to garbage to force build breaks in release builds
|
||||
@@ -694,31 +743,58 @@ inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultVal
|
||||
// missing or 0 -> don't break
|
||||
// 1 -> wait for the debugger, continue execution once it is attached
|
||||
// 2 -> wait for the debugger, break here once attached.
|
||||
namespace details
|
||||
{
|
||||
template <typename error_policy>
|
||||
inline void WaitForDebuggerPresent(bool checkRegistryConfig)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
DWORD configValue{1};
|
||||
if (checkRegistryConfig)
|
||||
{
|
||||
// err_returncode_policy will continue running after this line on failure. The default value of zero
|
||||
// will apply in that case so we will still behave reasonably.
|
||||
error_policy::HResult(details::GetCurrentProcessExecutionOptionNoThrow(L"WaitForDebuggerPresent", 0, &configValue));
|
||||
}
|
||||
|
||||
if (configValue == 0)
|
||||
{
|
||||
return; // not configured, don't wait
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
if (configValue == 2)
|
||||
{
|
||||
DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller
|
||||
}
|
||||
return; // debugger now attached, continue executing
|
||||
}
|
||||
Sleep(500);
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
#ifdef WIL_ENABLE_EXCEPTIONS
|
||||
inline void WaitForDebuggerPresent(bool checkRegistryConfig = true)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto configValue = checkRegistryConfig ? GetCurrentProcessExecutionOption(L"WaitForDebuggerPresent") : 1;
|
||||
if (configValue == 0)
|
||||
{
|
||||
return; // not configured, don't wait
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
if (configValue == 2)
|
||||
{
|
||||
DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller
|
||||
}
|
||||
return; // debugger now attached, continue executing
|
||||
}
|
||||
Sleep(500);
|
||||
}
|
||||
details::WaitForDebuggerPresent<err_exception_policy>(checkRegistryConfig);
|
||||
}
|
||||
#endif
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
#endif
|
||||
inline void WaitForDebuggerPresentNoThrow(bool checkRegistryConfig = true)
|
||||
{
|
||||
details::WaitForDebuggerPresent<err_returncode_policy>(checkRegistryConfig);
|
||||
}
|
||||
|
||||
inline void WaitForDebuggerPresentFailFast(bool checkRegistryConfig = true)
|
||||
{
|
||||
details::WaitForDebuggerPresent<err_failfast_policy>(checkRegistryConfig);
|
||||
}
|
||||
|
||||
#endif // DebugBreak
|
||||
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
||||
|
||||
/** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that
|
||||
the linker provides for every module. This avoids the need for a global HINSTANCE variable
|
||||
@@ -886,10 +962,8 @@ bool init_once(_Inout_ INIT_ONCE& initOnce, T func)
|
||||
completion.success();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // WIL_ENABLE_EXCEPTIONS
|
||||
|
||||
@@ -897,17 +971,40 @@ bool init_once(_Inout_ INIT_ONCE& initOnce, T func)
|
||||
/// @cond
|
||||
namespace details
|
||||
{
|
||||
// NOTE: We can't have a 'using std::begin' at class scope, hence the workaround for handling both 'begin' with ADL
|
||||
// and 'std::begin' separately. We want to handle both because there's no guarantee the type has a 'begin' method
|
||||
template <typename RangeT>
|
||||
struct deduce_char_type_from_string_range_traits
|
||||
{
|
||||
template <typename U>
|
||||
static std::true_type deduce_has_adl_begin(U&& range, std::void_t<decltype((*begin(range))[0])>*);
|
||||
template <typename U>
|
||||
static std::false_type deduce_has_adl_begin(U&&, ...);
|
||||
|
||||
template <typename U>
|
||||
static std::true_type deduce_has_std_begin(U&& range, std::void_t<decltype((*std::begin(range))[0])>*);
|
||||
template <typename U>
|
||||
static std::false_type deduce_has_std_begin(U&&, ...);
|
||||
|
||||
static constexpr bool has_adl_begin = decltype(deduce_has_adl_begin(std::declval<RangeT>(), nullptr))::value;
|
||||
static constexpr bool has_std_begin = decltype(deduce_has_std_begin(std::declval<RangeT>(), nullptr))::value;
|
||||
};
|
||||
|
||||
template <typename RangeT, bool hasAdlBegin = deduce_char_type_from_string_range_traits<RangeT>::has_adl_begin, bool hasStdBegin = deduce_char_type_from_string_range_traits<RangeT>::has_std_begin>
|
||||
struct deduce_char_type_from_string_range
|
||||
{
|
||||
template <typename T = RangeT>
|
||||
static auto deduce(T& range)
|
||||
{
|
||||
using std::begin;
|
||||
return (*begin(range))[0];
|
||||
}
|
||||
};
|
||||
|
||||
using type = decltype(deduce(wistd::declval<RangeT&>()));
|
||||
template <typename RangeT, bool hasStdBegin>
|
||||
struct deduce_char_type_from_string_range<RangeT, true, hasStdBegin>
|
||||
{
|
||||
using type = std::decay_t<decltype((*begin(std::declval<RangeT>()))[0])>;
|
||||
};
|
||||
|
||||
template <typename RangeT>
|
||||
struct deduce_char_type_from_string_range<RangeT, false, true>
|
||||
{
|
||||
using type = std::decay_t<decltype((*std::begin(std::declval<RangeT>()))[0])>;
|
||||
};
|
||||
|
||||
template <typename RangeT>
|
||||
@@ -979,6 +1076,7 @@ inline std::basic_string<CharT> ArgvToCommandLine(RangeT&& range, ArgvToCommandL
|
||||
// Somewhat of a hack to avoid the fact that we can't conditionalize a string literal on a template
|
||||
static constexpr const CharT empty_string[] = {'\0'};
|
||||
static constexpr const CharT single_quote_string[] = {'"', '\0'};
|
||||
static constexpr const CharT double_quote_string[] = {'"', '"', '\0'};
|
||||
static constexpr const CharT space_string[] = {' ', '\0'};
|
||||
static constexpr const CharT quoted_space_string[] = {'"', ' ', '"', '\0'};
|
||||
|
||||
@@ -996,6 +1094,7 @@ inline std::basic_string<CharT> ArgvToCommandLine(RangeT&& range, ArgvToCommandL
|
||||
{
|
||||
auto currentIndex = index++;
|
||||
result += prefix;
|
||||
prefix = nextPrefix;
|
||||
|
||||
const CharT* searchString = initialSearchString;
|
||||
|
||||
@@ -1005,6 +1104,14 @@ inline std::basic_string<CharT> ArgvToCommandLine(RangeT&& range, ArgvToCommandL
|
||||
|
||||
// We need to escape any quotes and CONDITIONALLY any backslashes
|
||||
string_view_type str(strRaw);
|
||||
if (str.empty() && !forceQuotes)
|
||||
{
|
||||
// The argument is empty. If we want to preserve it in the command line string, we need to manually insert
|
||||
// a pair of quotes since normal parsing won't handle this case
|
||||
result.append(double_quote_string);
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < str.size())
|
||||
{
|
||||
@@ -1023,7 +1130,9 @@ inline std::basic_string<CharT> ArgvToCommandLine(RangeT&& range, ArgvToCommandL
|
||||
result.append(str, pos, nextPos - pos);
|
||||
pos = nextPos;
|
||||
if (pos == str.npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (str[pos] == '"')
|
||||
{
|
||||
@@ -1102,8 +1211,6 @@ inline std::basic_string<CharT> ArgvToCommandLine(RangeT&& range, ArgvToCommandL
|
||||
{
|
||||
result.push_back('"');
|
||||
}
|
||||
|
||||
prefix = nextPrefix;
|
||||
}
|
||||
|
||||
// NOTE: We optimize the force quotes case by including them in the prefix string. We're not appending a prefix
|
||||
@@ -1137,6 +1244,6 @@ inline std::basic_string<wistd::remove_cv_t<CharT>> ArgvToCommandLine(
|
||||
// sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0);
|
||||
// }
|
||||
// Declaration
|
||||
#define GetProcAddressByFunctionDeclaration(hinst, fn) reinterpret_cast<decltype(::fn)*>(GetProcAddress(hinst, #fn))
|
||||
#define GetProcAddressByFunctionDeclaration(hinst, fn) (reinterpret_cast<decltype(::fn)*>(GetProcAddress(hinst, #fn)))
|
||||
|
||||
#endif // __WIL_WIN32_HELPERS_INCLUDED
|
||||
|
||||
+39
-4
@@ -115,8 +115,8 @@
|
||||
#define __WI_PUSH_WARNINGS __pragma(warning(push))
|
||||
#define __WI_POP_WARNINGS __pragma(warning(pop))
|
||||
#elif defined(__WI_LIBCPP_COMPILER_CLANG)
|
||||
#define __WI_PUSH_WARNINGS __pragma(clang diagnostic push)
|
||||
#define __WI_POP_WARNINGS __pragma(clang diagnostic pop)
|
||||
#define __WI_PUSH_WARNINGS _Pragma("clang diagnostic push")
|
||||
#define __WI_POP_WARNINGS _Pragma("clang diagnostic pop")
|
||||
#else
|
||||
#define __WI_PUSH_WARNINGS
|
||||
#define __WI_POP_WARNINGS
|
||||
@@ -129,7 +129,8 @@
|
||||
#endif
|
||||
|
||||
#ifdef __WI_LIBCPP_COMPILER_CLANG
|
||||
#define __WI_CLANG_DISABLE_WARNING(warning) __pragma(clang diagnostic ignored #warning)
|
||||
#define __WI_CLANG_DISABLE_WARNING_AUX(x) _Pragma(#x)
|
||||
#define __WI_CLANG_DISABLE_WARNING(w) __WI_CLANG_DISABLE_WARNING_AUX(clang diagnostic ignored #w)
|
||||
#else
|
||||
#define __WI_CLANG_DISABLE_WARNING(warning)
|
||||
#endif
|
||||
@@ -203,7 +204,11 @@
|
||||
#define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union)
|
||||
#define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class)
|
||||
#define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum)
|
||||
#ifdef __WI_LIBCPP_COMPILER_GCC
|
||||
#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 0
|
||||
#else
|
||||
#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to)
|
||||
#endif
|
||||
#define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty)
|
||||
#define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic)
|
||||
#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor)
|
||||
@@ -222,19 +227,33 @@
|
||||
#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403)
|
||||
#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403)
|
||||
|
||||
#ifdef __clang__
|
||||
#if !(__has_feature(cxx_noexcept))
|
||||
#define __WI_LIBCPP_HAS_NO_NOEXCEPT
|
||||
#endif
|
||||
#else
|
||||
#if __cplusplus < 201103L
|
||||
#define __WI_LIBCPP_HAS_NO_NOEXCEPT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700
|
||||
#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if !(__has_feature(cxx_variadic_templates))
|
||||
#define __WI_LIBCPP_HAS_NO_VARIADICS
|
||||
#endif
|
||||
#else
|
||||
#if __cplusplus < 201103L
|
||||
#define __WI_LIBCPP_HAS_NO_VARIADICS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __has_feature(is_literal) || __WI_GNUC_VER >= 407
|
||||
#if defined(__MINGW32__)
|
||||
#define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T)
|
||||
#elif __has_feature(is_literal) || __WI_GNUC_VER >= 407
|
||||
#define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T)
|
||||
#endif
|
||||
|
||||
@@ -258,13 +277,25 @@
|
||||
#define __WI_LIBCPP_NO_RTTI
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if !(__has_feature(cxx_variable_templates))
|
||||
#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
|
||||
#endif
|
||||
#else
|
||||
#if __cplusplus < 201103L
|
||||
#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if !(__has_feature(cxx_relaxed_constexpr))
|
||||
#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR
|
||||
#endif
|
||||
#else
|
||||
#if __cplusplus < 201103L
|
||||
#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700
|
||||
#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF
|
||||
@@ -473,7 +504,11 @@
|
||||
|
||||
namespace wistd // ("Windows Implementation" std)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
using nullptr_t = decltype(nullptr);
|
||||
#else
|
||||
using nullptr_t = decltype(__nullptr);
|
||||
#endif
|
||||
|
||||
template <class _T1, class _T2 = _T1>
|
||||
struct __less
|
||||
|
||||
+83
-50
@@ -388,23 +388,27 @@ __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v = is_void<_Tp>::valu
|
||||
|
||||
// __is_nullptr_t
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_nullptr_t_impl : public false_type
|
||||
namespace details
|
||||
{
|
||||
};
|
||||
template <>
|
||||
struct __is_nullptr_t_impl<nullptr_t> : public true_type
|
||||
{
|
||||
};
|
||||
template <class _Tp>
|
||||
struct is_nullptr_t_impl : false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_nullptr_t_impl<nullptr_t> : true_type
|
||||
{
|
||||
};
|
||||
} // namespace details
|
||||
|
||||
template <class _Tp>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t : details::is_nullptr_t_impl<typename remove_cv<_Tp>::type>
|
||||
{
|
||||
};
|
||||
|
||||
#if __WI_LIBCPP_STD_VER > 11
|
||||
template <class _Tp>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer : details::is_nullptr_t_impl<typename remove_cv<_Tp>::type>
|
||||
{
|
||||
};
|
||||
|
||||
@@ -1189,9 +1193,14 @@ using type_identity_t = typename type_identity<_Tp>::type;
|
||||
|
||||
// is_signed
|
||||
|
||||
__WI_PUSH_WARNINGS
|
||||
__WI_MSVC_DISABLE_WARNING(4296) // error C4296: '<': expression is always false
|
||||
|
||||
template <class _Tp, bool = is_integral<_Tp>::value>
|
||||
struct __libcpp_is_signed_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(-1) < _Tp(0)){};
|
||||
|
||||
__WI_POP_WARNINGS
|
||||
|
||||
template <class _Tp>
|
||||
struct __libcpp_is_signed_impl<_Tp, false> : public true_type
|
||||
{
|
||||
@@ -1488,18 +1497,18 @@ struct __WI_LIBCPP_TEMPLATE_VIS is_convertible
|
||||
|
||||
#else // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO
|
||||
|
||||
namespace __is_convertible_imp
|
||||
namespace wi_is_convertible_imp
|
||||
{
|
||||
template <class _Tp>
|
||||
void __test_convert(_Tp);
|
||||
|
||||
template <class _From, class _To, class = void>
|
||||
struct __is_convertible_test : public false_type
|
||||
struct wi_is_convertible_test : public false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class _From, class _To>
|
||||
struct __is_convertible_test<_From, _To, decltype(__is_convertible_imp::__test_convert<_To>(declval<_From>()))> : public true_type
|
||||
struct wi_is_convertible_test<_From, _To, decltype(wi_is_convertible_imp::__test_convert<_To>(declval<_From>()))> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
@@ -1535,16 +1544,16 @@ namespace __is_convertible_imp
|
||||
value = 3
|
||||
};
|
||||
};
|
||||
} // namespace __is_convertible_imp
|
||||
} // namespace wi_is_convertible_imp
|
||||
|
||||
template <class _Tp, unsigned = __is_convertible_imp::__is_array_function_or_void<typename remove_reference<_Tp>::type>::value>
|
||||
struct __is_convertible_check
|
||||
template <class _Tp, unsigned = wi_is_convertible_imp::__is_array_function_or_void<typename remove_reference<_Tp>::type>::value>
|
||||
struct wi_is_convertible_check
|
||||
{
|
||||
static const size_t __v = 0;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_convertible_check<_Tp, 0>
|
||||
struct wi_is_convertible_check<_Tp, 0>
|
||||
{
|
||||
static const size_t __v = sizeof(_Tp);
|
||||
};
|
||||
@@ -1552,12 +1561,12 @@ struct __is_convertible_check<_Tp, 0>
|
||||
template <
|
||||
class _T1,
|
||||
class _T2,
|
||||
unsigned _T1_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T1>::value,
|
||||
unsigned _T2_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T2>::value>
|
||||
struct __is_convertible
|
||||
unsigned _T1_is_array_function_or_void = wi_is_convertible_imp::__is_array_function_or_void<_T1>::value,
|
||||
unsigned _T2_is_array_function_or_void = wi_is_convertible_imp::__is_array_function_or_void<_T2>::value>
|
||||
struct wi_is_convertible
|
||||
: public integral_constant<
|
||||
bool,
|
||||
__is_convertible_imp::__is_convertible_test<_T1, _T2>::value
|
||||
wi_is_convertible_imp::wi_is_convertible_test<_T1, _T2>::value
|
||||
#if defined(__WI_LIBCPP_HAS_NO_RVALUE_REFERENCES)
|
||||
&& !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value &&
|
||||
(!is_const<typename remove_reference<_T2>::type>::value || is_volatile<typename remove_reference<_T2>::type>::value) &&
|
||||
@@ -1567,37 +1576,61 @@ struct __is_convertible
|
||||
>{};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 0, 1> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 1, 1> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 2, 1> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 3, 1> : public false_type{};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 0, 2> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 1, 2> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 2, 2> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 3, 2> : public false_type{};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 0, 3> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 1, 3> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 2, 3> : public false_type{};
|
||||
template <class _T1, class _T2>
|
||||
struct __is_convertible<_T1, _T2, 3, 3> : public true_type{};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS is_convertible : public __is_convertible<_T1, _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 0, 1> : public false_type
|
||||
{
|
||||
static const size_t __complete_check1 = __is_convertible_check<_T1>::__v;
|
||||
static const size_t __complete_check2 = __is_convertible_check<_T2>::__v;
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 1, 1> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 2, 1> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 3, 1> : public false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 0, 2> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 1, 2> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 2, 2> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 3, 2> : public false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 0, 3> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 1, 3> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 2, 3> : public false_type
|
||||
{
|
||||
};
|
||||
template <class _T1, class _T2>
|
||||
struct wi_is_convertible<_T1, _T2, 3, 3> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class _T1, class _T2>
|
||||
struct __WI_LIBCPP_TEMPLATE_VIS is_convertible : public wi_is_convertible<_T1, _T2>
|
||||
{
|
||||
static const size_t __complete_check1 = wi_is_convertible_check<_T1>::__v;
|
||||
static const size_t __complete_check2 = wi_is_convertible_check<_T2>::__v;
|
||||
};
|
||||
|
||||
#endif // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO
|
||||
|
||||
Reference in New Issue
Block a user