mirror of https://github.com/PCSX2/pcsx2.git
7298 lines
306 KiB
C++
7298 lines
306 KiB
C++
//*********************************************************
|
|
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// This code is licensed under the MIT License.
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
//
|
|
//*********************************************************
|
|
//! @file
|
|
//! WIL Error Handling Helpers: supporting file defining a family of macros and functions designed to uniformly handle errors
|
|
//! across return codes, fail fast, exceptions and logging.
|
|
#ifndef __WIL_RESULTMACROS_INCLUDED
|
|
#define __WIL_RESULTMACROS_INCLUDED
|
|
|
|
// WARNING:
|
|
// Code within this scope must satisfy both C99 and C++
|
|
|
|
#include "common.h"
|
|
|
|
#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
|
|
#include <Windows.h>
|
|
#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.
|
|
// RESULT_NO_DEBUG is provided as an opt-out mechanism.
|
|
#ifndef RESULT_DEBUG
|
|
#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(RESULT_NO_DEBUG) && (defined(WIL_KERNEL_MODE) || !defined(NDEBUG))
|
|
#define RESULT_DEBUG
|
|
#endif
|
|
#endif
|
|
|
|
/// @cond
|
|
#if defined(_PREFAST_)
|
|
#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp)
|
|
#else
|
|
#ifdef RESULT_DEBUG
|
|
#define __WI_ANALYSIS_ASSUME(_exp) ((void)0)
|
|
#else
|
|
// NOTE: Clang does not currently handle __noop correctly and will fail to compile if the argument is not copy
|
|
// constructible. Therefore, use 'sizeof' for syntax validation. We don't do this universally for all compilers
|
|
// since lambdas are not allowed in unevaluated contexts prior to C++20, which does not appear to affect __noop
|
|
#if !defined(_MSC_VER) || defined(__clang__)
|
|
#define __WI_ANALYSIS_ASSUME(_exp) ((void)sizeof(!(_exp))) // Validate syntax on non-debug builds
|
|
#else
|
|
#define __WI_ANALYSIS_ASSUME(_exp) __noop(_exp)
|
|
#endif
|
|
#endif
|
|
#endif // _PREFAST_
|
|
|
|
//*****************************************************************************
|
|
// Assert Macros
|
|
//*****************************************************************************
|
|
|
|
#ifdef RESULT_DEBUG
|
|
#if defined(__clang__) && defined(_WIN32)
|
|
// Clang currently mis-handles '__annotation' for 32-bit - https://bugs.llvm.org/show_bug.cgi?id=41890
|
|
#define __WI_ASSERT_FAIL_ANNOTATION(msg) (void)0
|
|
#else
|
|
#define __WI_ASSERT_FAIL_ANNOTATION(msg) __annotation(L"Debug", L"AssertFail", msg)
|
|
#endif
|
|
|
|
#define WI_ASSERT_FAIL(msg) __WI_ASSERT_FAIL_ANNOTATION(L"" msg), DbgRaiseAssertionFailure()
|
|
#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (WI_ASSERT_FAIL(#condition), FALSE) : TRUE))
|
|
#define WI_ASSERT_MSG(condition, msg) \
|
|
(__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE))
|
|
#define WI_ASSERT_NOASSUME WI_ASSERT
|
|
#define WI_ASSERT_MSG_NOASSUME WI_ASSERT_MSG
|
|
#define WI_VERIFY WI_ASSERT
|
|
#define WI_VERIFY_MSG WI_ASSERT_MSG
|
|
#define WI_VERIFY_SUCCEEDED(condition) WI_ASSERT(SUCCEEDED(condition))
|
|
#else
|
|
#define WI_ASSERT_FAIL(msg)
|
|
#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), 0)
|
|
#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), 0)
|
|
#define WI_ASSERT_NOASSUME(condition) ((void)0)
|
|
#define WI_ASSERT_MSG_NOASSUME(condition, msg) ((void)0)
|
|
#define WI_VERIFY(condition) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE))
|
|
#define WI_VERIFY_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE))
|
|
#define WI_VERIFY_SUCCEEDED(condition) (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE))
|
|
#endif // RESULT_DEBUG
|
|
|
|
#if !defined(_NTDEF_)
|
|
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
|
|
#endif
|
|
#ifndef STATUS_SUCCESS
|
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
|
#endif
|
|
#ifndef STATUS_UNSUCCESSFUL
|
|
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
|
|
#endif
|
|
#ifndef __NTSTATUS_FROM_WIN32
|
|
#define __NTSTATUS_FROM_WIN32(x) \
|
|
((NTSTATUS)(x) <= 0 ? ((NTSTATUS)(x)) : ((NTSTATUS)(((x)&0x0000FFFF) | (FACILITY_WIN32 << 16) | ERROR_SEVERITY_ERROR)))
|
|
#endif
|
|
|
|
#ifndef WIL_AllocateMemory
|
|
#ifdef _KERNEL_MODE
|
|
#define WIL_AllocateMemory(SIZE) ExAllocatePoolWithTag(NonPagedPoolNx, SIZE, 'LIW')
|
|
WI_ODR_PRAGMA("WIL_AllocateMemory", "2")
|
|
#else
|
|
#define WIL_AllocateMemory(SIZE) HeapAlloc(GetProcessHeap(), 0, SIZE)
|
|
WI_ODR_PRAGMA("WIL_AllocateMemory", "1")
|
|
#endif
|
|
#else
|
|
WI_ODR_PRAGMA("WIL_AllocateMemory", "0")
|
|
#endif
|
|
|
|
#ifndef WIL_FreeMemory
|
|
#ifdef _KERNEL_MODE
|
|
#define WIL_FreeMemory(MEM) ExFreePoolWithTag(MEM, 'LIW')
|
|
WI_ODR_PRAGMA("WIL_FreeMemory", "2")
|
|
#else
|
|
#define WIL_FreeMemory(MEM) HeapFree(GetProcessHeap(), 0, MEM)
|
|
WI_ODR_PRAGMA("WIL_FreeMemory", "1")
|
|
#endif
|
|
#else
|
|
WI_ODR_PRAGMA("WIL_FreeMemory", "0")
|
|
#endif
|
|
|
|
// It would appear as though the C++17 "noexcept is part of the type system" update in MSVC has "infected" the behavior
|
|
// when compiling with C++14 (the default...), however the updated behavior for decltype understanding noexcept is _not_
|
|
// present... So, work around it
|
|
#if __WI_LIBCPP_STD_VER >= 17
|
|
#define WI_PFN_NOEXCEPT WI_NOEXCEPT
|
|
#else
|
|
#define WI_PFN_NOEXCEPT
|
|
#endif
|
|
/// @endcond
|
|
|
|
#if defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
|
|
|
|
#include <strsafe.h>
|
|
#include <intrin.h> // provides the _ReturnAddress() intrinsic
|
|
#include <new.h> // provides 'operator new', 'std::nothrow', etc.
|
|
#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW)
|
|
#include <new> // provides std::bad_alloc in the windows and public CRT headers
|
|
#endif
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4714 6262) // __forceinline not honored, stack size
|
|
|
|
//*****************************************************************************
|
|
// Behavioral setup (error handling macro configuration)
|
|
//*****************************************************************************
|
|
// Set any of the following macros to the values given below before including Result.h to
|
|
// control the error handling macro's trade-offs between diagnostics and performance
|
|
|
|
// RESULT_DIAGNOSTICS_LEVEL
|
|
// This define controls the level of diagnostic instrumentation that is built into the binary as a
|
|
// byproduct of using the macros. The amount of diagnostic instrumentation that is supplied is
|
|
// a trade-off between diagnosibility of issues and code size and performance. The modes are:
|
|
// 0 - No diagnostics, smallest & fastest (subject to tail-merge)
|
|
// 1 - No diagnostics, unique call sites for each macro (defeat's tail-merge)
|
|
// 2 - Line number
|
|
// 3 - Line number + source filename
|
|
// 4 - Line number + source filename + function name
|
|
// 5 - Line number + source filename + function name + code within the macro
|
|
// By default, mode 3 is used in free builds and mode 5 is used in checked builds. Note that the
|
|
// _ReturnAddress() will always be available through all modes when possible.
|
|
|
|
// RESULT_INCLUDE_CALLER_RETURNADDRESS
|
|
// This controls whether or not the _ReturnAddress() of the function that includes the macro will
|
|
// be reported to telemetry. Note that this is in addition to the _ReturnAddress() of the actual
|
|
// macro position (which is always reported). The values are:
|
|
// 0 - The address is not included
|
|
// 1 - The address is included
|
|
// The default value is '1'.
|
|
|
|
// RESULT_INLINE_ERROR_TESTS
|
|
// For conditional macros (other than RETURN_XXX), this controls whether branches will be evaluated
|
|
// within the call containing the macro or will be forced into the function called by the macros.
|
|
// Pushing branching into the called function reduces code size and the number of unique branches
|
|
// evaluated, but increases the instruction count executed per macro.
|
|
// 0 - Branching will not happen inline to the macros
|
|
// 1 - Branching is pushed into the calling function via __forceinline
|
|
// The default value is '1'. Note that XXX_MSG functions are always effectively mode '0' due to the
|
|
// compiler's unwillingness to inline var-arg functions.
|
|
|
|
// RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST
|
|
// RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST
|
|
// RESULT_INLINE_ERROR_TESTS_FAIL_FAST
|
|
// These defines are identical to those above in form/function, but only applicable to fail fast error
|
|
// handling allowing a process to have different diagnostic information and performance characteristics
|
|
// for fail fast than for other error handling given the different reporting infrastructure (Watson
|
|
// vs Telemetry).
|
|
|
|
// Set the default diagnostic mode
|
|
// Note that RESULT_DEBUG_INFO and RESULT_SUPPRESS_DEBUG_INFO are older deprecated models of controlling mode
|
|
/// @cond
|
|
#ifndef RESULT_DIAGNOSTICS_LEVEL
|
|
#if (defined(RESULT_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO)
|
|
#define RESULT_DIAGNOSTICS_LEVEL 5
|
|
#else
|
|
#define RESULT_DIAGNOSTICS_LEVEL 3
|
|
#endif
|
|
#endif
|
|
#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS
|
|
#define RESULT_INCLUDE_CALLER_RETURNADDRESS 1
|
|
#endif
|
|
#ifndef RESULT_INLINE_ERROR_TESTS
|
|
#define RESULT_INLINE_ERROR_TESTS 1
|
|
#endif
|
|
#ifndef RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST
|
|
#define RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST RESULT_DIAGNOSTICS_LEVEL
|
|
#endif
|
|
#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST
|
|
#define RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST RESULT_INCLUDE_CALLER_RETURNADDRESS
|
|
#endif
|
|
#ifndef RESULT_INLINE_ERROR_TESTS_FAIL_FAST
|
|
#define RESULT_INLINE_ERROR_TESTS_FAIL_FAST RESULT_INLINE_ERROR_TESTS
|
|
#endif
|
|
/// @endcond
|
|
|
|
//*****************************************************************************
|
|
// Win32 specific error macros
|
|
//*****************************************************************************
|
|
|
|
#define FAILED_WIN32(win32err) ((win32err) != 0)
|
|
#define SUCCEEDED_WIN32(win32err) ((win32err) == 0)
|
|
|
|
//*****************************************************************************
|
|
// NT_STATUS specific error macros
|
|
//*****************************************************************************
|
|
|
|
#define FAILED_NTSTATUS(status) (((NTSTATUS)(status)) < 0)
|
|
#define SUCCEEDED_NTSTATUS(status) (((NTSTATUS)(status)) >= 0)
|
|
|
|
//*****************************************************************************
|
|
// Testing helpers - redefine to run unit tests against fail fast
|
|
//*****************************************************************************
|
|
/// @cond
|
|
#ifndef RESULT_NORETURN
|
|
#define RESULT_NORETURN __declspec(noreturn)
|
|
#endif
|
|
#ifndef RESULT_NORETURN_NULL
|
|
#define RESULT_NORETURN_NULL _Ret_notnull_
|
|
#endif
|
|
#ifndef RESULT_NORETURN_RESULT
|
|
#define RESULT_NORETURN_RESULT(expr) (void)(expr);
|
|
#endif
|
|
/// @endcond
|
|
|
|
//*****************************************************************************
|
|
// Helpers to setup the macros and functions used below... do not directly use.
|
|
//*****************************************************************************
|
|
|
|
/// @cond
|
|
#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
|
|
#define __R_FN_PARAMS_FULL \
|
|
_In_opt_ void *callerReturnAddress, unsigned int lineNumber, _In_opt_ PCSTR fileName, _In_opt_ PCSTR functionName, \
|
|
_In_opt_ PCSTR code, void *returnAddress
|
|
#define __R_FN_LOCALS_FULL_RA \
|
|
void* callerReturnAddress = nullptr; \
|
|
unsigned int lineNumber = 0; \
|
|
PCSTR fileName = nullptr; \
|
|
PCSTR functionName = nullptr; \
|
|
PCSTR code = nullptr; \
|
|
void* returnAddress = _ReturnAddress();
|
|
// NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases
|
|
// This entire section will be repeated below for fail fast (__RFF_ prefix).
|
|
#define __R_COMMA ,
|
|
#define __R_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress
|
|
#define __R_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress()
|
|
// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly
|
|
#if (RESULT_DIAGNOSTICS_LEVEL >= 2) // line number
|
|
#define __R_IF_LINE(term) term
|
|
#define __R_IF_NOT_LINE(term)
|
|
#define __R_IF_COMMA ,
|
|
#define __R_LINE_VALUE static_cast<unsigned short>(__LINE__)
|
|
#else
|
|
#define __R_IF_LINE(term)
|
|
#define __R_IF_NOT_LINE(term) term
|
|
#define __R_IF_COMMA
|
|
#define __R_LINE_VALUE static_cast<unsigned short>(0)
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL >= 3) // line number + file name
|
|
#define __R_IF_FILE(term) term
|
|
#define __R_IF_NOT_FILE(term)
|
|
#define __R_FILE_VALUE __FILE__
|
|
#else
|
|
#define __R_IF_FILE(term)
|
|
#define __R_IF_NOT_FILE(term) term
|
|
#define __R_FILE_VALUE nullptr
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL >= 4) // line number + file name + function name
|
|
#define __R_IF_FUNCTION(term) term
|
|
#define __R_IF_NOT_FUNCTION(term)
|
|
#else
|
|
#define __R_IF_FUNCTION(term)
|
|
#define __R_IF_NOT_FUNCTION(term) term
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL >= 5) // line number + file name + function name + macro code
|
|
#define __R_IF_CODE(term) term
|
|
#define __R_IF_NOT_CODE(term)
|
|
#else
|
|
#define __R_IF_CODE(term)
|
|
#define __R_IF_NOT_CODE(term) term
|
|
#endif
|
|
#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1)
|
|
#define __R_IF_CALLERADDRESS(term) term
|
|
#define __R_IF_NOT_CALLERADDRESS(term)
|
|
#define __R_CALLERADDRESS_VALUE _ReturnAddress()
|
|
#else
|
|
#define __R_IF_CALLERADDRESS(term)
|
|
#define __R_IF_NOT_CALLERADDRESS(term) term
|
|
#define __R_CALLERADDRESS_VALUE nullptr
|
|
#endif
|
|
#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) || (RESULT_DIAGNOSTICS_LEVEL >= 2)
|
|
#define __R_IF_TRAIL_COMMA ,
|
|
#else
|
|
#define __R_IF_TRAIL_COMMA
|
|
#endif
|
|
// Assemble the varying amounts of data into a single macro
|
|
#define __R_INFO_ONLY(CODE) \
|
|
__R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \
|
|
__R_IF_LINE(__R_LINE_VALUE) \
|
|
__R_IF_FILE(__R_COMMA __R_FILE_VALUE) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE)
|
|
#define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA
|
|
#define __R_INFO_NOFILE_ONLY(CODE) \
|
|
__R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) \
|
|
__R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE)
|
|
#define __R_INFO_NOFILE(CODE) __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA
|
|
#define __R_FN_PARAMS_ONLY \
|
|
__R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) \
|
|
__R_IF_LINE(unsigned int lineNumber) \
|
|
__R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) \
|
|
__R_IF_FUNCTION(__R_COMMA _In_opt_ PCSTR functionName) __R_IF_CODE(__R_COMMA _In_opt_ PCSTR code)
|
|
#define __R_FN_PARAMS __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA
|
|
#define __R_FN_CALL_ONLY \
|
|
__R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) \
|
|
__R_IF_LINE(lineNumber) __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code)
|
|
#define __R_FN_CALL __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA
|
|
#define __R_FN_LOCALS \
|
|
__R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \
|
|
__R_IF_NOT_LINE(unsigned int lineNumber = 0;) \
|
|
__R_IF_NOT_FILE(PCSTR fileName = nullptr;) \
|
|
__R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;)
|
|
#define __R_FN_LOCALS_RA \
|
|
__R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \
|
|
__R_IF_NOT_LINE(unsigned int lineNumber = 0;) \
|
|
__R_IF_NOT_FILE(PCSTR fileName = nullptr;) \
|
|
__R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) \
|
|
__R_IF_NOT_CODE(PCSTR code = nullptr;) void* returnAddress = _ReturnAddress();
|
|
#define __R_FN_UNREFERENCED \
|
|
__R_IF_CALLERADDRESS((void)callerReturnAddress;) \
|
|
__R_IF_LINE((void)lineNumber;) __R_IF_FILE((void)fileName;) __R_IF_FUNCTION((void)functionName;) __R_IF_CODE((void)code;)
|
|
// 1) Direct Methods
|
|
// * Called Directly by Macros
|
|
// * Always noinline
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#define __R_DIRECT_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RetType MethodName
|
|
#define __R_DIRECT_NORET_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
|
#else
|
|
#define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
|
#endif
|
|
#define __R_DIRECT_FN_PARAMS __R_FN_PARAMS
|
|
#define __R_DIRECT_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY
|
|
#define __R_DIRECT_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA
|
|
#define __R_DIRECT_FN_CALL_ONLY __R_FN_CALL_FULL_RA
|
|
// 2) Internal Methods
|
|
// * Only called by Conditional routines
|
|
// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined)
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName
|
|
#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __R_INTERNAL_INLINE_METHOD(MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) void MethodName
|
|
#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName<optimizerCounter>
|
|
#else
|
|
#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName
|
|
#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName
|
|
#define __R_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName
|
|
#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName
|
|
#endif
|
|
#define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName
|
|
#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void* returnAddress __R_COMMA
|
|
#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void* returnAddress
|
|
#define __R_INTERNAL_NOINLINE_FN_CALL __R_FN_CALL_FULL __R_COMMA
|
|
#define __R_INTERNAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL_FULL
|
|
#define __R_INTERNAL_INLINE_FN_PARAMS __R_FN_PARAMS
|
|
#define __R_INTERNAL_INLINE_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY
|
|
#define __R_INTERNAL_INLINE_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA
|
|
#define __R_INTERNAL_INLINE_FN_CALL_ONLY __R_FN_CALL_FULL_RA
|
|
#if (RESULT_INLINE_ERROR_TESTS == 0)
|
|
#define __R_INTERNAL_METHOD __R_INTERNAL_NOINLINE_METHOD
|
|
#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_NOINLINE_NORET_METHOD
|
|
#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_NOINLINE_METHOD
|
|
#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_NOINLINE_FN_PARAMS
|
|
#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY
|
|
#define __R_INTERNAL_FN_CALL __R_INTERNAL_NOINLINE_FN_CALL
|
|
#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_NOINLINE_FN_CALL_ONLY
|
|
#else
|
|
#define __R_INTERNAL_METHOD __R_INTERNAL_INLINE_METHOD
|
|
#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_INLINE_NORET_METHOD
|
|
#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_INLINE_METHOD
|
|
#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_INLINE_FN_PARAMS
|
|
#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_INLINE_FN_PARAMS_ONLY
|
|
#define __R_INTERNAL_FN_CALL __R_INTERNAL_INLINE_FN_CALL
|
|
#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_INLINE_FN_CALL_ONLY
|
|
#endif
|
|
// 3) Conditional Methods
|
|
// * Called Directly by Macros
|
|
// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS)
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RetType MethodName
|
|
#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
__forceinline RetType MethodName
|
|
#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __R_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __R_COMMA
|
|
#else
|
|
#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __R_CONDITIONAL_PARTIAL_TEMPLATE
|
|
#endif
|
|
#define __R_CONDITIONAL_NOINLINE_FN_CALL __R_FN_CALL _ReturnAddress() __R_COMMA
|
|
#define __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL _ReturnAddress()
|
|
#define __R_CONDITIONAL_INLINE_FN_CALL __R_FN_CALL
|
|
#define __R_CONDITIONAL_INLINE_FN_CALL_ONLY __R_FN_CALL_ONLY
|
|
#if (RESULT_INLINE_ERROR_TESTS == 0)
|
|
#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_NOINLINE_METHOD
|
|
#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD
|
|
#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_NOINLINE_FN_CALL
|
|
#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY
|
|
#else
|
|
#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_INLINE_METHOD
|
|
#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_INLINE_TEMPLATE_METHOD
|
|
#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_INLINE_FN_CALL
|
|
#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_INLINE_FN_CALL_ONLY
|
|
#endif
|
|
#define __R_CONDITIONAL_FN_PARAMS __R_FN_PARAMS
|
|
#define __R_CONDITIONAL_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY
|
|
// Macro call-site helpers
|
|
#define __R_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes
|
|
#define __R_NS_ASSEMBLE(ri, rd) __R_NS_ASSEMBLE2(ri, rd)
|
|
#define __R_NS_NAME __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL)
|
|
#define __R_NS wil::details::__R_NS_NAME
|
|
#if (RESULT_DIAGNOSTICS_LEVEL == 1)
|
|
#define __R_FN(MethodName) __R_NS::MethodName<__COUNTER__>
|
|
#else
|
|
#define __R_FN(MethodName) __R_NS::MethodName
|
|
#endif
|
|
// NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases
|
|
// This entire section is repeated below for fail fast (__RFF_ prefix). For ease of editing this section, the
|
|
// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST),
|
|
// (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST)
|
|
#define __RFF_COMMA ,
|
|
#define __RFF_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress
|
|
#define __RFF_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress()
|
|
// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) // line number
|
|
#define __RFF_IF_LINE(term) term
|
|
#define __RFF_IF_NOT_LINE(term)
|
|
#define __RFF_IF_COMMA ,
|
|
#else
|
|
#define __RFF_IF_LINE(term)
|
|
#define __RFF_IF_NOT_LINE(term) term
|
|
#define __RFF_IF_COMMA
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 3) // line number + file name
|
|
#define __RFF_IF_FILE(term) term
|
|
#define __RFF_IF_NOT_FILE(term)
|
|
#else
|
|
#define __RFF_IF_FILE(term)
|
|
#define __RFF_IF_NOT_FILE(term) term
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 4) // line number + file name + function name
|
|
#define __RFF_IF_FUNCTION(term) term
|
|
#define __RFF_IF_NOT_FUNCTION(term)
|
|
#else
|
|
#define __RFF_IF_FUNCTION(term)
|
|
#define __RFF_IF_NOT_FUNCTION(term) term
|
|
#endif
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 5) // line number + file name + function name + macro code
|
|
#define __RFF_IF_CODE(term) term
|
|
#define __RFF_IF_NOT_CODE(term)
|
|
#else
|
|
#define __RFF_IF_CODE(term)
|
|
#define __RFF_IF_NOT_CODE(term) term
|
|
#endif
|
|
#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1)
|
|
#define __RFF_IF_CALLERADDRESS(term) term
|
|
#define __RFF_IF_NOT_CALLERADDRESS(term)
|
|
#else
|
|
#define __RFF_IF_CALLERADDRESS(term)
|
|
#define __RFF_IF_NOT_CALLERADDRESS(term) term
|
|
#endif
|
|
#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) || (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2)
|
|
#define __RFF_IF_TRAIL_COMMA ,
|
|
#else
|
|
#define __RFF_IF_TRAIL_COMMA
|
|
#endif
|
|
// Assemble the varying amounts of data into a single macro
|
|
#define __RFF_INFO_ONLY(CODE) \
|
|
__RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) \
|
|
__RFF_IF_LINE(__R_LINE_VALUE) \
|
|
__RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE)
|
|
#define __RFF_INFO(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)
|
|
#define __RFF_INFO_NOFILE(CODE) __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA
|
|
#define __RFF_FN_PARAMS_ONLY \
|
|
__RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) \
|
|
__RFF_IF_LINE(unsigned int lineNumber) \
|
|
__RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) \
|
|
__RFF_IF_FUNCTION(__RFF_COMMA _In_opt_ PCSTR functionName) __RFF_IF_CODE(__RFF_COMMA _In_opt_ PCSTR code)
|
|
#define __RFF_FN_PARAMS __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA
|
|
#define __RFF_FN_CALL_ONLY \
|
|
__RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) \
|
|
__RFF_IF_LINE(lineNumber) \
|
|
__RFF_IF_FILE(__RFF_COMMA fileName) __RFF_IF_FUNCTION(__RFF_COMMA functionName) __RFF_IF_CODE(__RFF_COMMA code)
|
|
#define __RFF_FN_CALL __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA
|
|
#define __RFF_FN_LOCALS \
|
|
__RFF_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) \
|
|
__RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) \
|
|
__RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) \
|
|
__RFF_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __RFF_IF_NOT_CODE(PCSTR code = nullptr;)
|
|
#define __RFF_FN_UNREFERENCED \
|
|
__RFF_IF_CALLERADDRESS(callerReturnAddress;) \
|
|
__RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;)
|
|
// 1) Direct Methods
|
|
// * Called Directly by Macros
|
|
// * Always noinline
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#define __RFF_DIRECT_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
|
#else
|
|
#define __RFF_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName
|
|
#endif
|
|
#define __RFF_DIRECT_FN_PARAMS __RFF_FN_PARAMS
|
|
#define __RFF_DIRECT_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY
|
|
#define __RFF_DIRECT_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA
|
|
#define __RFF_DIRECT_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA
|
|
// 2) Internal Methods
|
|
// * Only called by Conditional routines
|
|
// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise noinline (directly called by code when branching is forceinlined)
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName
|
|
#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __RFF_INTERNAL_INLINE_METHOD(MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) void MethodName
|
|
#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName<optimizerCounter>
|
|
#else
|
|
#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName
|
|
#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName
|
|
#define __RFF_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName
|
|
#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName
|
|
#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName
|
|
#endif
|
|
#define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName
|
|
#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void* returnAddress __RFF_COMMA
|
|
#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void* returnAddress
|
|
#define __RFF_INTERNAL_NOINLINE_FN_CALL __RFF_FN_CALL_FULL __RFF_COMMA
|
|
#define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL
|
|
#define __RFF_INTERNAL_INLINE_FN_PARAMS __RFF_FN_PARAMS
|
|
#define __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY
|
|
#define __RFF_INTERNAL_INLINE_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA
|
|
#define __RFF_INTERNAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA
|
|
#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0)
|
|
#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_NOINLINE_METHOD
|
|
#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_NOINLINE_NORET_METHOD
|
|
#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_NOINLINE_METHOD
|
|
#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_NOINLINE_FN_PARAMS
|
|
#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY
|
|
#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_NOINLINE_FN_CALL
|
|
#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY
|
|
#else
|
|
#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_INLINE_METHOD
|
|
#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_INLINE_NORET_METHOD
|
|
#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_INLINE_METHOD
|
|
#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_INLINE_FN_PARAMS
|
|
#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY
|
|
#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_INLINE_FN_CALL
|
|
#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_INLINE_FN_CALL_ONLY
|
|
#endif
|
|
// 3) Conditional Methods
|
|
// * Called Directly by Macros
|
|
// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST)
|
|
// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) \
|
|
template <unsigned int optimizerCounter> \
|
|
__forceinline RetType MethodName
|
|
#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __RFF_COMMA
|
|
#else
|
|
#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName
|
|
#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName
|
|
#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE
|
|
#endif
|
|
#define __RFF_CONDITIONAL_NOINLINE_FN_CALL __RFF_FN_CALL _ReturnAddress() __RFF_COMMA
|
|
#define __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL _ReturnAddress()
|
|
#define __RFF_CONDITIONAL_INLINE_FN_CALL __RFF_FN_CALL
|
|
#define __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_ONLY
|
|
#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0)
|
|
#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_NOINLINE_METHOD
|
|
#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD
|
|
#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_NOINLINE_FN_CALL
|
|
#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY
|
|
#else
|
|
#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_INLINE_METHOD
|
|
#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD
|
|
#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_INLINE_FN_CALL
|
|
#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY
|
|
#endif
|
|
#define __RFF_CONDITIONAL_FN_PARAMS __RFF_FN_PARAMS
|
|
#define __RFF_CONDITIONAL_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY
|
|
// Macro call-site helpers
|
|
#define __RFF_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes
|
|
#define __RFF_NS_ASSEMBLE(ri, rd) __RFF_NS_ASSEMBLE2(ri, rd)
|
|
#define __RFF_NS_NAME __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST)
|
|
#define __RFF_NS wil::details::__RFF_NS_NAME
|
|
#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
|
|
#define __RFF_FN(MethodName) __RFF_NS::MethodName<__COUNTER__>
|
|
#else
|
|
#define __RFF_FN(MethodName) __RFF_NS::MethodName
|
|
#endif
|
|
// end-of-repeated fail-fast handling macros
|
|
|
|
// Force the compiler to evaluate a call to 'wprintf' to verify the format string & args and produce warnings if there
|
|
// are any issues. The short-circuit 'and' will prevent the call and strings used from making it into the binary.
|
|
// Note that this requires using a string literal for the format string. If you don't, you'll get the following compiler
|
|
// error: error C2146: syntax error: missing ')' before identifier '...'
|
|
#if !defined(wprintf) && !defined(WIL_NO_MSG_FORMAT_CHECKS)
|
|
#define __WI_CHECK_MSG_FMT(fmt, ...) (0 && ::wprintf(L"" fmt, ##__VA_ARGS__)) ? nullptr : fmt, ##__VA_ARGS__
|
|
#else
|
|
#define __WI_CHECK_MSG_FMT(fmt, ...) fmt, ##__VA_ARGS__
|
|
#endif
|
|
|
|
// Helpers for return macros
|
|
#define __RETURN_HR_MSG(hr, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
if (FAILED(__hr)) \
|
|
{ \
|
|
__R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
} \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
__R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_WIN32_MSG(err, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __err = (err); \
|
|
if (FAILED_WIN32(__err)) \
|
|
{ \
|
|
return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
} \
|
|
return S_OK; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __err = (err); \
|
|
return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) \
|
|
return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __status = (status); \
|
|
if (FAILED_NTSTATUS(__status)) \
|
|
{ \
|
|
return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
} \
|
|
return S_OK; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __status = (status); \
|
|
return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_HR(hr, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
if (FAILED(__hr)) \
|
|
{ \
|
|
__R_FN(Return_Hr)(__R_INFO(str) __hr); \
|
|
} \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_HR_NOFILE(hr, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
if (FAILED(__hr)) \
|
|
{ \
|
|
__R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \
|
|
} \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_HR_FAIL(hr, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
__R_FN(Return_Hr)(__R_INFO(str) __hr); \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_HR_FAIL_NOFILE(hr, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const HRESULT __hr = (hr); \
|
|
__R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); \
|
|
return __hr; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_WIN32(err, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __err = (err); \
|
|
if (FAILED_WIN32(__err)) \
|
|
{ \
|
|
return __R_FN(Return_Win32)(__R_INFO(str) __err); \
|
|
} \
|
|
return S_OK; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_WIN32_FAIL(err, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __err = (err); \
|
|
return __R_FN(Return_Win32)(__R_INFO(str) __err); \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_GLE_FAIL(str) return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str))
|
|
#define __RETURN_GLE_FAIL_NOFILE(str) return __R_FN(Return_GetLastError)(__R_INFO_NOFILE_ONLY(str))
|
|
#define __RETURN_NTSTATUS(status, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __status = (status); \
|
|
if (FAILED_NTSTATUS(__status)) \
|
|
{ \
|
|
return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \
|
|
} \
|
|
return S_OK; \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define __RETURN_NTSTATUS_FAIL(status, str) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __status = (status); \
|
|
return __R_FN(Return_NtStatus)(__R_INFO(str) __status); \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
/// @endcond
|
|
|
|
//*****************************************************************************
|
|
// Macros for returning failures as HRESULTs
|
|
//*****************************************************************************
|
|
|
|
// Always returns a known result (HRESULT) - always logs failures
|
|
#define RETURN_HR(hr) __RETURN_HR(wil::verify_hresult(hr), #hr)
|
|
#define RETURN_LAST_ERROR() __RETURN_GLE_FAIL(nullptr)
|
|
#define RETURN_WIN32(win32err) __RETURN_WIN32(win32err, #win32err)
|
|
#define RETURN_NTSTATUS(status) __RETURN_NTSTATUS(status, #status)
|
|
|
|
// Conditionally returns failures (HRESULT) - always logs failures
|
|
#define RETURN_IF_FAILED(hr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const auto __hrRet = wil::verify_hresult(hr); \
|
|
if (FAILED(__hrRet)) \
|
|
{ \
|
|
__RETURN_HR_FAIL(__hrRet, #hr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const auto __boolRet = wil::verify_BOOL(win32BOOL); \
|
|
if (!__boolRet) \
|
|
{ \
|
|
__RETURN_GLE_FAIL(#win32BOOL); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_ERROR(win32err) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __errRet = (win32err); \
|
|
if (FAILED_WIN32(__errRet)) \
|
|
{ \
|
|
__RETURN_WIN32_FAIL(__errRet, #win32err); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NULL_ALLOC(ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF(hr, condition) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
__RETURN_HR(wil::verify_hresult(hr), #condition); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF_NULL(hr, ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_HR(wil::verify_hresult(hr), #ptr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF(condition) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
__RETURN_GLE_FAIL(#condition); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF_NULL(ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_GLE_FAIL(#ptr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NTSTATUS_FAILED(status) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __statusRet = (status); \
|
|
if (FAILED_NTSTATUS(__statusRet)) \
|
|
{ \
|
|
__RETURN_NTSTATUS_FAIL(__statusRet, #status); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
|
|
// Always returns a known failure (HRESULT) - always logs a var-arg message on failure
|
|
#define RETURN_HR_MSG(hr, fmt, ...) __RETURN_HR_MSG(wil::verify_hresult(hr), #hr, fmt, ##__VA_ARGS__)
|
|
#define RETURN_LAST_ERROR_MSG(fmt, ...) __RETURN_GLE_MSG_FAIL(nullptr, fmt, ##__VA_ARGS__)
|
|
#define RETURN_WIN32_MSG(win32err, fmt, ...) __RETURN_WIN32_MSG(win32err, #win32err, fmt, ##__VA_ARGS__)
|
|
#define RETURN_NTSTATUS_MSG(status, fmt, ...) __RETURN_NTSTATUS_MSG(status, #status, fmt, ##__VA_ARGS__)
|
|
|
|
// Conditionally returns failures (HRESULT) - always logs a var-arg message on failure
|
|
#define RETURN_IF_FAILED_MSG(hr, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const auto __hrRet = wil::verify_hresult(hr); \
|
|
if (FAILED(__hrRet)) \
|
|
{ \
|
|
__RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (!wil::verify_BOOL(win32BOOL)) \
|
|
{ \
|
|
__RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __errRet = (win32err); \
|
|
if (FAILED_WIN32(__errRet)) \
|
|
{ \
|
|
__RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
__RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
__RETURN_GLE_MSG_FAIL(#condition, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_GLE_MSG_FAIL(#ptr, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __statusRet = (status); \
|
|
if (FAILED_NTSTATUS(__statusRet)) \
|
|
{ \
|
|
__RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, ##__VA_ARGS__); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
|
|
// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern
|
|
#define RETURN_IF_FAILED_EXPECTED(hr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const auto __hrRet = wil::verify_hresult(hr); \
|
|
if (FAILED(__hrRet)) \
|
|
{ \
|
|
return __hrRet; \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (!wil::verify_BOOL(win32BOOL)) \
|
|
{ \
|
|
return wil::details::GetLastErrorFailHr(); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const DWORD __errRet = (win32err); \
|
|
if (FAILED_WIN32(__errRet)) \
|
|
{ \
|
|
return __HRESULT_FROM_WIN32(__errRet); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
return E_OUTOFMEMORY; \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF_EXPECTED(hr, condition) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
return wil::verify_hresult(hr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
return wil::verify_hresult(hr); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF_EXPECTED(condition) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if (wil::verify_bool(condition)) \
|
|
{ \
|
|
return wil::details::GetLastErrorFailHr(); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
return wil::details::GetLastErrorFailHr(); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) \
|
|
__WI_SUPPRESS_4127_S do \
|
|
{ \
|
|
const NTSTATUS __statusRet = (status); \
|
|
if (FAILED_NTSTATUS(__statusRet)) \
|
|
{ \
|
|
return wil::details::NtStatusToHr(__statusRet); \
|
|
} \
|
|
} \
|
|
__WI_SUPPRESS_4127_E while ((void)0, 0)
|
|
|
|
/// @cond
|
|
#define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e))
|
|
/// @endcond
|
|
#define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \
|
|
do \
|
|
{ \
|
|
const auto __hrRet = wil::verify_hresult(hr); \
|
|
if (FAILED(__hrRet)) \
|
|
{ \
|
|
if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \
|
|
{ \
|
|
return __hrRet; \
|
|
} \
|
|
__RETURN_HR_FAIL(__hrRet, #hr); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
|
|
//*****************************************************************************
|
|
// Macros for logging failures (ignore or pass-through)
|
|
//*****************************************************************************
|
|
|
|
// 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)
|
|
|
|
// 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_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)
|
|
|
|
// Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures
|
|
#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr))
|
|
#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr))
|
|
#define SUCCEEDED_WIN32_LOG(win32err) SUCCEEDED_WIN32(LOG_IF_WIN32_ERROR(win32err))
|
|
#define FAILED_WIN32_LOG(win32err) FAILED_WIN32(LOG_IF_WIN32_ERROR(win32err))
|
|
#define SUCCEEDED_NTSTATUS_LOG(status) SUCCEEDED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status))
|
|
#define FAILED_NTSTATUS_LOG(status) FAILED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status))
|
|
|
|
// Alternatives for NT_SUCCESS(x) that conditionally logs failures
|
|
#define NT_SUCCESS_LOG(status) NT_SUCCESS(LOG_IF_NTSTATUS_FAILED(status))
|
|
|
|
// Always logs a known failure - logs a var-arg message on failure
|
|
#define LOG_HR_MSG(hr, fmt, ...) __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_LAST_ERROR_MSG(fmt, ...) __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_WIN32_MSG(win32err, fmt, ...) \
|
|
__R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_NTSTATUS_MSG(status, fmt, ...) \
|
|
__R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Conditionally logs failures - returns parameter value - logs a var-arg message on failure
|
|
#define LOG_IF_FAILED_MSG(hr, fmt, ...) \
|
|
__R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \
|
|
__R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \
|
|
__R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \
|
|
__R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_HR_IF_MSG(hr, condition, fmt, ...) \
|
|
__R_FN(Log_HrIfMsg) \
|
|
(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \
|
|
__R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) \
|
|
__R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \
|
|
__R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \
|
|
__R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
/// @cond
|
|
#define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e)
|
|
/// @endcond
|
|
#define LOG_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \
|
|
__R_FN(Log_IfFailedWithExpected) \
|
|
(__R_INFO(#hr) wil::verify_hresult(hr), \
|
|
WI_ARGS_COUNT(__VA_ARGS__) + 1, \
|
|
wil::verify_hresult(hrExpected) WI_FOREACH(__WI_COMMA_EXPECTED_HRESULT, ##__VA_ARGS__))
|
|
|
|
//*****************************************************************************
|
|
// Macros to fail fast the process on failures
|
|
//*****************************************************************************
|
|
|
|
// 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)
|
|
|
|
// 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_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)
|
|
|
|
// Always fail fast a known failure - fail fast a var-arg message on failure
|
|
#define FAIL_FAST_HR_MSG(hr, fmt, ...) \
|
|
__RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) \
|
|
__RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) \
|
|
__RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) \
|
|
__RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure
|
|
#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) \
|
|
__RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \
|
|
__RFF_FN(FailFast_IfWin32BoolFalseMsg) \
|
|
(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \
|
|
__RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \
|
|
__RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) \
|
|
__RFF_FN(FailFast_HrIfMsg) \
|
|
(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \
|
|
__RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) \
|
|
__RFF_FN(FailFast_GetLastErrorIfMsg) \
|
|
(__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \
|
|
__RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \
|
|
__RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Always fail fast a known failure
|
|
#ifndef FAIL_FAST
|
|
#define FAIL_FAST() __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(nullptr))
|
|
#endif
|
|
|
|
// 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)
|
|
|
|
// 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__))
|
|
|
|
// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure
|
|
#define FAIL_FAST_IF_MSG(condition, fmt, ...) \
|
|
__RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...) \
|
|
__RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state)
|
|
#define FAIL_FAST_IMMEDIATE() __RFF_FN(FailFastImmediate_Unexpected)()
|
|
|
|
// Conditional immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state)
|
|
#define FAIL_FAST_IMMEDIATE_IF_FAILED(hr) __RFF_FN(FailFastImmediate_IfFailed)(wil::verify_hresult(hr))
|
|
#define FAIL_FAST_IMMEDIATE_IF(condition) __RFF_FN(FailFastImmediate_If)(wil::verify_bool(condition))
|
|
#define FAIL_FAST_IMMEDIATE_IF_NULL(ptr) __RFF_FN(FailFastImmediate_IfNull)(ptr)
|
|
#define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status)
|
|
|
|
// Specializations
|
|
#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() \
|
|
do \
|
|
{ \
|
|
if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) \
|
|
{ \
|
|
wil::details::g_pfnFailFastInLoaderCallout(); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
|
|
// Like 'FAIL_FAST_IF', but raises an assertion failure first for easier debugging
|
|
#define WI_FAIL_FAST_ASSERT(condition) \
|
|
do \
|
|
{ \
|
|
if (!wil::verify_bool(condition)) \
|
|
{ \
|
|
WI_ASSERT_FAIL(#condition); \
|
|
__RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)) \
|
|
} \
|
|
} while (0, 0)
|
|
#define WI_FAIL_FAST_ASSERT_MSG(condition, msg) \
|
|
do \
|
|
{ \
|
|
if (!wil::verify_bool(condition)) \
|
|
{ \
|
|
WI_ASSERT_FAIL(msg); \
|
|
__RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(#condition) __WI_CHECK_MSG_FMT(msg)); \
|
|
} \
|
|
} while (0, 0)
|
|
|
|
//*****************************************************************************
|
|
// Macros to throw exceptions on failure
|
|
//*****************************************************************************
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
|
|
// 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)
|
|
|
|
// 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_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)
|
|
|
|
// Always throw a known failure - throw a var-arg message on failure
|
|
#define THROW_HR_MSG(hr, fmt, ...) \
|
|
__R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_LAST_ERROR_MSG(fmt, ...) __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_WIN32_MSG(win32err, fmt, ...) \
|
|
__R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_EXCEPTION_MSG(exception, fmt, ...) \
|
|
wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_NTSTATUS_MSG(status, fmt, ...) \
|
|
__R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Conditionally throw failures - returns parameter value - throw a var-arg message on failure
|
|
#define THROW_IF_FAILED_MSG(hr, fmt, ...) \
|
|
__R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) \
|
|
__R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) \
|
|
__R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) \
|
|
__R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_HR_IF_MSG(hr, condition, fmt, ...) \
|
|
__R_FN(Throw_HrIfMsg) \
|
|
(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) \
|
|
__R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_WIN32_IF_MSG(win32err, condition, fmt, ...) \
|
|
__R_FN(Throw_Win32IfMsg) \
|
|
(__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) \
|
|
__R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) \
|
|
__R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) \
|
|
__R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
//*****************************************************************************
|
|
// Macros to catch and convert exceptions on failure
|
|
//*****************************************************************************
|
|
|
|
// Use these macros *within* a catch (...) block to handle exceptions
|
|
#define RETURN_CAUGHT_EXCEPTION() return __R_FN(Return_CaughtException)(__R_INFO_ONLY(nullptr))
|
|
#define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) \
|
|
return __R_FN(Return_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define RETURN_CAUGHT_EXCEPTION_EXPECTED() return wil::ResultFromCaughtException()
|
|
#define LOG_CAUGHT_EXCEPTION() __R_FN(Log_CaughtException)(__R_INFO_ONLY(nullptr))
|
|
#define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...) \
|
|
__R_FN(Log_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define FAIL_FAST_CAUGHT_EXCEPTION() __R_FN(FailFast_CaughtException)(__R_INFO_ONLY(nullptr))
|
|
#define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...) \
|
|
__R_FN(FailFast_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
#define THROW_NORMALIZED_CAUGHT_EXCEPTION() __R_FN(Throw_CaughtException)(__R_INFO_ONLY(nullptr))
|
|
#define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...) \
|
|
__R_FN(Throw_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__))
|
|
|
|
// Use these macros in place of a catch block to handle exceptions
|
|
#define CATCH_RETURN() \
|
|
catch (...) \
|
|
{ \
|
|
RETURN_CAUGHT_EXCEPTION(); \
|
|
}
|
|
#define CATCH_RETURN_MSG(fmt, ...) \
|
|
catch (...) \
|
|
{ \
|
|
RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
|
}
|
|
#define CATCH_RETURN_EXPECTED() \
|
|
catch (...) \
|
|
{ \
|
|
RETURN_CAUGHT_EXCEPTION_EXPECTED(); \
|
|
}
|
|
#define CATCH_LOG() \
|
|
catch (...) \
|
|
{ \
|
|
LOG_CAUGHT_EXCEPTION(); \
|
|
}
|
|
// Use CATCH_LOG_RETURN instead of CATCH_LOG in a function-try block around a destructor. CATCH_LOG in this specific case has an
|
|
// implicit throw at the end of scope. Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept throws exception) is
|
|
// detected even when the throwing code is unreachable, such as the end of scope after a return, in function-level catch.
|
|
#define CATCH_LOG_RETURN() \
|
|
catch (...) \
|
|
{ \
|
|
__pragma(warning(suppress : 4297)); \
|
|
LOG_CAUGHT_EXCEPTION(); \
|
|
return; \
|
|
}
|
|
#define CATCH_LOG_MSG(fmt, ...) \
|
|
catch (...) \
|
|
{ \
|
|
LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
|
}
|
|
// Likewise use CATCH_LOG_RETURN_MSG instead of CATCH_LOG_MSG in function-try blocks around destructors.
|
|
#define CATCH_LOG_RETURN_MSG(fmt, ...) \
|
|
catch (...) \
|
|
{ \
|
|
__pragma(warning(suppress : 4297)); \
|
|
LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
|
return; \
|
|
}
|
|
#define CATCH_FAIL_FAST() \
|
|
catch (...) \
|
|
{ \
|
|
FAIL_FAST_CAUGHT_EXCEPTION(); \
|
|
}
|
|
#define CATCH_FAIL_FAST_MSG(fmt, ...) \
|
|
catch (...) \
|
|
{ \
|
|
FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
|
}
|
|
#define CATCH_THROW_NORMALIZED() \
|
|
catch (...) \
|
|
{ \
|
|
THROW_NORMALIZED_CAUGHT_EXCEPTION(); \
|
|
}
|
|
#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) \
|
|
catch (...) \
|
|
{ \
|
|
THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); \
|
|
}
|
|
#define CATCH_LOG_RETURN_HR(hr) \
|
|
catch (...) \
|
|
{ \
|
|
LOG_CAUGHT_EXCEPTION(); \
|
|
return hr; \
|
|
}
|
|
|
|
#endif // WIL_ENABLE_EXCEPTIONS
|
|
|
|
// Use this macro to supply diagnostics information to wil::ResultFromException
|
|
#define WI_DIAGNOSTICS_INFO wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE)
|
|
#define WI_DIAGNOSTICS_NAME(name) wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE, name)
|
|
|
|
//*****************************************************************************
|
|
// Usage Error Macros
|
|
//*****************************************************************************
|
|
|
|
#ifndef WI_USAGE_ASSERT_STOP
|
|
#define WI_USAGE_ASSERT_STOP(condition) WI_ASSERT(condition)
|
|
#endif
|
|
#ifdef RESULT_DEBUG
|
|
#define WI_USAGE_ERROR(msg, ...) \
|
|
do \
|
|
{ \
|
|
LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); \
|
|
WI_USAGE_ASSERT_STOP(false); \
|
|
} while ((void)0, 0)
|
|
#define WI_USAGE_ERROR_FORWARD(msg, ...) \
|
|
do \
|
|
{ \
|
|
ReportFailure_ReplaceMsg<FailureType::Log>(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); \
|
|
WI_USAGE_ASSERT_STOP(false); \
|
|
} while ((void)0, 0)
|
|
#else
|
|
#define WI_USAGE_ERROR(msg, ...) \
|
|
do \
|
|
{ \
|
|
LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \
|
|
WI_USAGE_ASSERT_STOP(false); \
|
|
} while ((void)0, 0)
|
|
#define WI_USAGE_ERROR_FORWARD(msg, ...) \
|
|
do \
|
|
{ \
|
|
ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); \
|
|
WI_USAGE_ASSERT_STOP(false); \
|
|
} while ((void)0, 0)
|
|
#endif
|
|
#define WI_USAGE_VERIFY(condition, msg, ...) \
|
|
do \
|
|
{ \
|
|
const auto __passed = wil::verify_bool(condition); \
|
|
if (!__passed) \
|
|
{ \
|
|
WI_USAGE_ERROR(msg, ##__VA_ARGS__); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) \
|
|
do \
|
|
{ \
|
|
const auto __passed = wil::verify_bool(condition); \
|
|
if (!__passed) \
|
|
{ \
|
|
WI_USAGE_ERROR_FORWARD(msg, ##__VA_ARGS__); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#ifdef RESULT_DEBUG
|
|
#define WI_USAGE_ASSERT(condition, msg, ...) WI_USAGE_VERIFY(condition, msg, ##__VA_ARGS__)
|
|
#else
|
|
#define WI_USAGE_ASSERT(condition, msg, ...)
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
// Internal Error Macros - DO NOT USE - these are for internal WIL use only to reduce sizes of binaries that use WIL
|
|
//*****************************************************************************
|
|
/// @cond
|
|
#ifdef RESULT_DEBUG
|
|
#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) RETURN_IF_FAILED(hr)
|
|
#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) RETURN_HR_IF(hr, cond)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) RETURN_LAST_ERROR_IF(cond)
|
|
#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) RETURN_IF_WIN32_BOOL_FALSE(win32BOOL)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) RETURN_LAST_ERROR_IF_NULL(ptr)
|
|
#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) RETURN_IF_NULL_ALLOC(ptr)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR() RETURN_LAST_ERROR()
|
|
#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) FAIL_FAST_HR_IF(hr, condition)
|
|
#define __WIL_PRIVATE_FAIL_FAST_HR(hr) FAIL_FAST_HR(hr)
|
|
#define __WIL_PRIVATE_LOG_HR(hr) LOG_HR(hr)
|
|
#else
|
|
#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) \
|
|
do \
|
|
{ \
|
|
const auto __hrRet = wil::verify_hresult(hr); \
|
|
if (FAILED(__hrRet)) \
|
|
{ \
|
|
__RETURN_HR_FAIL_NOFILE(__hrRet, #hr); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) \
|
|
do \
|
|
{ \
|
|
if (wil::verify_bool(cond)) \
|
|
{ \
|
|
__RETURN_HR_NOFILE(wil::verify_hresult(hr), #cond); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) \
|
|
do \
|
|
{ \
|
|
if (wil::verify_bool(cond)) \
|
|
{ \
|
|
__RETURN_GLE_FAIL_NOFILE(#cond); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) \
|
|
do \
|
|
{ \
|
|
const BOOL __boolRet = wil::verify_BOOL(win32BOOL); \
|
|
if (!__boolRet) \
|
|
{ \
|
|
__RETURN_GLE_FAIL_NOFILE(#win32BOOL); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) \
|
|
do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_GLE_FAIL_NOFILE(#ptr); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) \
|
|
do \
|
|
{ \
|
|
if ((ptr) == nullptr) \
|
|
{ \
|
|
__RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __WIL_PRIVATE_RETURN_LAST_ERROR() __RETURN_GLE_FAIL_NOFILE(nullptr)
|
|
#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) \
|
|
__RFF_FN(FailFast_HrIf)(__RFF_INFO_NOFILE(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
|
|
#define __WIL_PRIVATE_FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO_NOFILE(#hr) wil::verify_hresult(hr))
|
|
#define __WIL_PRIVATE_LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO_NOFILE(#hr) wil::verify_hresult(hr))
|
|
#endif
|
|
/// @endcond
|
|
|
|
namespace wil
|
|
{
|
|
// Indicates the kind of message / failure type that was used to produce a given error
|
|
enum class FailureType
|
|
{
|
|
Exception, // THROW_...
|
|
Return, // RETURN_..._LOG or RETURN_..._MSG
|
|
Log, // LOG_...
|
|
FailFast // FAIL_FAST_...
|
|
};
|
|
|
|
enum class FailureFlags
|
|
{
|
|
None = 0x00,
|
|
RequestFailFast = 0x01,
|
|
RequestSuppressTelemetry = 0x02,
|
|
RequestDebugBreak = 0x04,
|
|
NtStatus = 0x08,
|
|
};
|
|
DEFINE_ENUM_FLAG_OPERATORS(FailureFlags);
|
|
|
|
/** Use with functions and macros that allow customizing which kinds of exceptions are handled.
|
|
This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */
|
|
enum class SupportedExceptions
|
|
{
|
|
Default, //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions).
|
|
Known, //!< [Known] all well known exceptions (including std::exception).
|
|
All, //!< [All] all exceptions, known or otherwise.
|
|
None, //!< [None] no exceptions at all, an exception will fail-fast where thrown.
|
|
Thrown, //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException).
|
|
ThrownOrAlloc //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or std::bad_alloc.
|
|
};
|
|
|
|
// Represents the call context information about a given failure
|
|
// No constructors, destructors or virtual members should be contained within
|
|
struct CallContextInfo
|
|
{
|
|
long contextId; // incrementing ID for this call context (unique across an individual module load within process)
|
|
PCSTR contextName; // the explicit name given to this context
|
|
PCWSTR contextMessage; // [optional] Message that can be associated with the call context
|
|
};
|
|
|
|
// Represents all context information about a given failure
|
|
// No constructors, destructors or virtual members should be contained within
|
|
struct FailureInfo
|
|
{
|
|
FailureType type;
|
|
FailureFlags flags;
|
|
HRESULT hr;
|
|
NTSTATUS status;
|
|
long failureId; // incrementing ID for this specific failure (unique across an individual module load within process)
|
|
PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message)
|
|
DWORD threadId; // the thread this failure was originally encountered on
|
|
PCSTR pszCode; // [debug only] Capture code from the macro
|
|
PCSTR pszFunction; // [debug only] The function name
|
|
PCSTR pszFile;
|
|
unsigned int uLineNumber;
|
|
int cFailureCount; // How many failures of 'type' have been reported in this module so far
|
|
PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure
|
|
CallContextInfo callContextOriginating; // The outermost (first seen) call context
|
|
CallContextInfo callContextCurrent; // The most recently seen call context
|
|
PCSTR pszModule; // The module where the failure originated
|
|
void* returnAddress; // The return address to the point that called the macro
|
|
void* callerReturnAddress; // The return address of the function that includes the macro
|
|
};
|
|
|
|
//! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions.
|
|
//! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions as parameters
|
|
//! hidden behind a macro. In some cases, the user needs to directly supply these, so this class provides the mechanism for that.
|
|
//! We only use this for user-passed content as it can't be directly controlled by RESULT_DIAGNOSTICS_LEVEL to ensure there are no
|
|
//! ODR violations (though that variable still controls what parameters within this structure would be available).
|
|
struct DiagnosticsInfo
|
|
{
|
|
void* returnAddress = nullptr;
|
|
PCSTR file = nullptr;
|
|
PCSTR name = nullptr;
|
|
unsigned short line = 0;
|
|
|
|
DiagnosticsInfo() = default;
|
|
|
|
__forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_) :
|
|
returnAddress(returnAddress_), file(file_), line(line_)
|
|
{
|
|
}
|
|
|
|
__forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) :
|
|
returnAddress(returnAddress_), file(file_), name(name_), line(line_)
|
|
{
|
|
}
|
|
};
|
|
|
|
enum class ErrorReturn
|
|
{
|
|
Auto,
|
|
None
|
|
};
|
|
|
|
// [optionally] Plug in error logging
|
|
// Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or
|
|
// SetResultLoggingCallback for observation.
|
|
extern "C" __declspec(selectany) void(__stdcall* g_pfnResultLoggingCallback)(
|
|
_Inout_ wil::FailureInfo* pFailure,
|
|
_Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage,
|
|
_Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// [optional]
|
|
// This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can also
|
|
// be set directly from within the debugger to force console logging for debugging purposes.
|
|
__declspec(selectany) bool g_fResultOutputDebugString = true;
|
|
|
|
// [optionally] Allows application to specify a debugger to detect whether a debugger is present.
|
|
// Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns
|
|
// false.
|
|
__declspec(selectany) bool(__stdcall* g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached and ::IsDebuggerPresent returns false
|
|
__declspec(selectany) bool g_fIsDebuggerPresent = false;
|
|
|
|
// [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception)
|
|
__declspec(selectany) HRESULT(__stdcall* g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// [optionally] Use to configure fast fail of unknown exceptions (turn them off).
|
|
__declspec(selectany) bool g_fResultFailFastUnknownExceptions = true;
|
|
|
|
// [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^
|
|
__declspec(selectany) bool g_fResultThrowPlatformException = true;
|
|
|
|
// [optionally] Set to false to a configure all CATCH_ and CAUGHT_ macros to NOT support (fail-fast) std::exception based exceptions (other than std::bad_alloc and wil::ResultException)
|
|
__declspec(selectany) bool g_fResultSupportStdException = true;
|
|
|
|
// [optionally] Set to true to cause a debug break to occur on a result failure
|
|
__declspec(selectany) bool g_fBreakOnFailure = false;
|
|
|
|
// [optionally] customize failfast behavior
|
|
__declspec(selectany) bool(__stdcall* g_pfnWilFailFast)(const wil::FailureInfo& info) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
// True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function)
|
|
__declspec(selectany) bool g_resultMessageCallbackSet = false;
|
|
|
|
// On Desktop/System WINAPI family: convert NTSTATUS error codes to friendly name strings.
|
|
__declspec(selectany) void(__stdcall* g_pfnFormatNtStatusMsg)(NTSTATUS, PWSTR, DWORD) = nullptr;
|
|
|
|
_Success_(true)
|
|
_Ret_range_(dest, destEnd)
|
|
inline PWSTR LogStringPrintf(
|
|
_Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest,
|
|
_Pre_satisfies_(destEnd >= dest) PCWSTR destEnd,
|
|
_In_ _Printf_format_string_ PCWSTR format,
|
|
...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, format);
|
|
StringCchVPrintfW(dest, (destEnd - dest), format, argList);
|
|
return (destEnd == dest) ? dest : (dest + wcslen(dest));
|
|
}
|
|
} // namespace details
|
|
/// @endcond
|
|
|
|
// This call generates the default logging string that makes its way to OutputDebugString for
|
|
// any particular failure. This string is also used to associate a failure with a PlatformException^ which
|
|
// only allows a single string to be associated with the exception.
|
|
inline HRESULT GetFailureLogString(
|
|
_Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest,
|
|
_Pre_satisfies_(cchDest > 0) _In_ size_t cchDest,
|
|
_In_ FailureInfo const& failure) WI_NOEXCEPT
|
|
{
|
|
// This function was lenient to empty strings at one point and some callers became dependent on this beahvior
|
|
if ((cchDest == 0) || (pszDest == nullptr))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
pszDest[0] = L'\0';
|
|
|
|
// Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console
|
|
// or the platform exception object if the caller desires it.
|
|
if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet)
|
|
{
|
|
// older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be modifying
|
|
g_pfnResultLoggingCallback(const_cast<FailureInfo*>(&failure), pszDest, cchDest);
|
|
}
|
|
|
|
// The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want
|
|
// it for OutputDebugString or exception message, then generate the default string.
|
|
if (pszDest[0] == L'\0')
|
|
{
|
|
PCSTR pszType = "";
|
|
switch (failure.type)
|
|
{
|
|
case FailureType::Exception:
|
|
pszType = "Exception";
|
|
break;
|
|
case FailureType::Return:
|
|
if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus))
|
|
{
|
|
pszType = "ReturnNt";
|
|
}
|
|
else
|
|
{
|
|
pszType = "ReturnHr";
|
|
}
|
|
break;
|
|
case FailureType::Log:
|
|
if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus))
|
|
{
|
|
pszType = "LogNt";
|
|
}
|
|
else
|
|
{
|
|
pszType = "LogHr";
|
|
}
|
|
break;
|
|
case FailureType::FailFast:
|
|
pszType = "FailFast";
|
|
break;
|
|
}
|
|
|
|
wchar_t szErrorText[256]{};
|
|
LONG errorCode = 0;
|
|
|
|
if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus))
|
|
{
|
|
errorCode = failure.status;
|
|
if (wil::details::g_pfnFormatNtStatusMsg)
|
|
{
|
|
wil::details::g_pfnFormatNtStatusMsg(failure.status, szErrorText, ARRAYSIZE(szErrorText));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorCode = failure.hr;
|
|
FormatMessageW(
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
nullptr,
|
|
failure.hr,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
szErrorText,
|
|
ARRAYSIZE(szErrorText),
|
|
nullptr);
|
|
}
|
|
|
|
// %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage
|
|
// %Caller_MSG [%CODE(%FUNCTION)]
|
|
|
|
PWSTR dest = pszDest;
|
|
PCWSTR destEnd = (pszDest + cchDest);
|
|
|
|
if (failure.pszFile != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(
|
|
dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress);
|
|
}
|
|
else
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress);
|
|
}
|
|
|
|
if (failure.callerReturnAddress != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress);
|
|
}
|
|
|
|
dest = details::LogStringPrintf(
|
|
dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), errorCode, szErrorText);
|
|
|
|
if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr))
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L" ");
|
|
if (failure.pszMessage != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage);
|
|
}
|
|
if (failure.pszCallContext != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext);
|
|
}
|
|
|
|
if (failure.pszCode != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode);
|
|
}
|
|
else if (failure.pszFunction != nullptr)
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction);
|
|
}
|
|
else
|
|
{
|
|
dest = details::LogStringPrintf(dest, destEnd, L"\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Explicitly choosing to return success in the event of truncation... Current callers
|
|
// depend upon it or it would be eliminated.
|
|
return S_OK;
|
|
}
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
//! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context where
|
|
//! exceptions or errors can be observed and logged.
|
|
struct IFunctor
|
|
{
|
|
virtual HRESULT Run() = 0;
|
|
};
|
|
|
|
//! Used to provide custom behavior when an exception is encountered while executing IFunctor
|
|
struct IFunctorHost
|
|
{
|
|
virtual HRESULT Run(IFunctor& functor) = 0;
|
|
virtual HRESULT ExceptionThrown(void* returnAddress) = 0;
|
|
};
|
|
|
|
__declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT;
|
|
__declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT) WI_NOEXCEPT;
|
|
|
|
struct ResultStatus
|
|
{
|
|
enum class Kind : unsigned int
|
|
{
|
|
HResult,
|
|
NtStatus
|
|
};
|
|
|
|
static ResultStatus FromResult(const HRESULT _hr)
|
|
{
|
|
return {_hr, wil::details::HrToNtStatus(_hr), Kind::HResult};
|
|
}
|
|
static ResultStatus FromStatus(const NTSTATUS _status)
|
|
{
|
|
return {wil::details::NtStatusToHr(_status), _status, Kind::NtStatus};
|
|
}
|
|
static ResultStatus FromFailureInfo(const FailureInfo& _failure)
|
|
{
|
|
return {_failure.hr, _failure.status, WI_IsFlagSet(_failure.flags, FailureFlags::NtStatus) ? Kind::NtStatus : Kind::HResult};
|
|
}
|
|
HRESULT hr = S_OK;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
Kind kind = Kind::NtStatus;
|
|
};
|
|
|
|
// Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback)
|
|
__declspec(selectany) void(__stdcall* g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Result.h plug-in (WIL use only)
|
|
__declspec(selectany) void(__stdcall* g_pfnNotifyFailure)(_Inout_ FailureInfo* pFailure) WI_PFN_NOEXCEPT = nullptr;
|
|
__declspec(selectany) void(__stdcall* g_pfnGetContextAndNotifyFailure)(
|
|
_Inout_ FailureInfo* pFailure,
|
|
_Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString,
|
|
_Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging
|
|
__declspec(selectany) void(__stdcall* g_pfnLoggingCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Desktop/System Only: Module fetch function (automatically setup)
|
|
__declspec(selectany) PCSTR(__stdcall* g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Desktop/System Only: Retrieve address offset and modulename
|
|
__declspec(selectany) bool(__stdcall* g_pfnGetModuleInformation)(
|
|
void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Called with the expectation that the program will terminate when called inside of a loader callout.
|
|
// Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
|
|
__declspec(selectany) void(__stdcall* g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Called to translate an NTSTATUS value to a Win32 error code
|
|
// Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
|
|
__declspec(selectany) ULONG(__stdcall* g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Desktop/System Only: Call to DebugBreak
|
|
__declspec(selectany) void(__stdcall* g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Called to determine whether or not termination is happening
|
|
// Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
|
|
__declspec(selectany) BOOLEAN(__stdcall* g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr;
|
|
__declspec(selectany) bool g_processShutdownInProgress = false;
|
|
|
|
// On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules
|
|
// that do not have RaiseFailFastException in kernelbase. UWP apps will directly link.
|
|
__declspec(selectany) void(__stdcall* g_pfnRaiseFailFastException)(PEXCEPTION_RECORD, PCONTEXT, DWORD) = nullptr;
|
|
|
|
// Exception-based compiled additions
|
|
__declspec(selectany)
|
|
HRESULT(__stdcall* g_pfnRunFunctorWithExceptionFilter)(IFunctor& functor, IFunctorHost& host, void* returnAddress) = nullptr;
|
|
__declspec(selectany) void(__stdcall* g_pfnRethrow)() = nullptr;
|
|
__declspec(selectany) void(__stdcall* g_pfnThrowResultException)(const FailureInfo& failure) = nullptr;
|
|
extern "C" __declspec(selectany) ResultStatus(__stdcall* g_pfnResultFromCaughtExceptionInternal)(
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// C++/WinRT additions
|
|
extern "C" __declspec(selectany) HRESULT(__stdcall* g_pfnResultFromCaughtException_CppWinRt)(
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// C++/cx compiled additions
|
|
extern "C" __declspec(selectany) void(__stdcall* g_pfnThrowPlatformException)(FailureInfo const& failure, PCWSTR debugString) = nullptr;
|
|
extern "C" __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall* g_pfnResultFromCaughtException_WinRt)(
|
|
_Inout_updates_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr;
|
|
__declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall* g_pfnResultFromKnownExceptions_WinRt)(
|
|
const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) = nullptr;
|
|
|
|
// Plugin to call RoOriginateError (WIL use only)
|
|
__declspec(selectany) void(__stdcall* g_pfnOriginateCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Plugin to call RoFailFastWithErrorContext (WIL use only)
|
|
__declspec(selectany) void(__stdcall* g_pfnFailfastWithContextCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
// Allocate and disown the allocation so that Appverifier does not complain about a false leak
|
|
inline PVOID ProcessHeapAlloc(_In_ DWORD flags, _In_ size_t size) WI_NOEXCEPT
|
|
{
|
|
const HANDLE processHeap = ::GetProcessHeap();
|
|
const PVOID allocation = ::HeapAlloc(processHeap, flags, size);
|
|
|
|
static bool fetchedRtlDisownModuleHeapAllocation = false;
|
|
static NTSTATUS(__stdcall * pfnRtlDisownModuleHeapAllocation)(HANDLE, PVOID) WI_PFN_NOEXCEPT = nullptr;
|
|
|
|
if (pfnRtlDisownModuleHeapAllocation)
|
|
{
|
|
(void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation);
|
|
}
|
|
else if (!fetchedRtlDisownModuleHeapAllocation)
|
|
{
|
|
if (auto ntdllModule = ::GetModuleHandleW(L"ntdll.dll"))
|
|
{
|
|
pfnRtlDisownModuleHeapAllocation = reinterpret_cast<decltype(pfnRtlDisownModuleHeapAllocation)>(
|
|
::GetProcAddress(ntdllModule, "RtlDisownModuleHeapAllocation"));
|
|
}
|
|
fetchedRtlDisownModuleHeapAllocation = true;
|
|
|
|
if (pfnRtlDisownModuleHeapAllocation)
|
|
{
|
|
(void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation);
|
|
}
|
|
}
|
|
|
|
return allocation;
|
|
}
|
|
|
|
enum class ReportFailureOptions
|
|
{
|
|
None = 0x00,
|
|
ForcePlatformException = 0x01,
|
|
MayRethrow = 0x02,
|
|
};
|
|
DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions);
|
|
|
|
template <typename TFunctor>
|
|
using functor_return_type = decltype((*static_cast<TFunctor*>(nullptr))());
|
|
|
|
template <typename TFunctor>
|
|
struct functor_wrapper_void : public IFunctor
|
|
{
|
|
TFunctor&& functor;
|
|
functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward<TFunctor>(functor_))
|
|
{
|
|
}
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2
|
|
HRESULT Run() override
|
|
{
|
|
functor();
|
|
return S_OK;
|
|
}
|
|
#pragma warning(pop)
|
|
};
|
|
|
|
template <typename TFunctor>
|
|
struct functor_wrapper_HRESULT : public IFunctor
|
|
{
|
|
TFunctor&& functor;
|
|
functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward<TFunctor>(functor_))
|
|
{
|
|
}
|
|
HRESULT Run() override
|
|
{
|
|
return functor();
|
|
}
|
|
};
|
|
|
|
template <typename TFunctor, typename TReturn>
|
|
struct functor_wrapper_other : public IFunctor
|
|
{
|
|
TFunctor&& functor;
|
|
TReturn& retVal;
|
|
functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward<TFunctor>(functor_)), retVal(retval_)
|
|
{
|
|
}
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4702) // https://github.com/Microsoft/wil/issues/2
|
|
HRESULT Run() override
|
|
{
|
|
retVal = functor();
|
|
return S_OK;
|
|
}
|
|
#pragma warning(pop)
|
|
};
|
|
|
|
struct tag_return_void : public wistd::integral_constant<size_t, 0>
|
|
{
|
|
template <typename TFunctor>
|
|
using functor_wrapper = functor_wrapper_void<TFunctor>;
|
|
};
|
|
|
|
struct tag_return_HRESULT : public wistd::integral_constant<size_t, 1>
|
|
{
|
|
template <typename TFunctor>
|
|
using functor_wrapper = functor_wrapper_HRESULT<TFunctor>;
|
|
};
|
|
|
|
struct tag_return_other : public wistd::integral_constant<size_t, 2>
|
|
{
|
|
template <typename TFunctor, typename TReturn>
|
|
using functor_wrapper = functor_wrapper_other<TFunctor, TReturn>;
|
|
};
|
|
|
|
// type-trait to help discover the return type of a functor for tag/dispatch.
|
|
|
|
template <ErrorReturn errorReturn, typename T>
|
|
struct return_type
|
|
{
|
|
using type = tag_return_other;
|
|
};
|
|
|
|
template <>
|
|
struct return_type<ErrorReturn::Auto, HRESULT>
|
|
{
|
|
using type = tag_return_HRESULT;
|
|
};
|
|
|
|
template <>
|
|
struct return_type<ErrorReturn::Auto, void>
|
|
{
|
|
using type = tag_return_void;
|
|
};
|
|
|
|
template <>
|
|
struct return_type<ErrorReturn::None, void>
|
|
{
|
|
using type = tag_return_void;
|
|
};
|
|
|
|
template <ErrorReturn errorReturn, typename Functor>
|
|
using functor_tag = typename return_type<errorReturn, functor_return_type<Functor>>::type;
|
|
|
|
// Forward declarations to enable use of fail fast and reporting internally...
|
|
namespace __R_NS_NAME
|
|
{
|
|
_Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == hr)
|
|
__R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == err)
|
|
__R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT;
|
|
} // namespace __R_NS_NAME
|
|
namespace __RFF_NS_NAME
|
|
{
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT;
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT;
|
|
} // namespace __RFF_NS_NAME
|
|
|
|
RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& info);
|
|
inline void LogFailure(
|
|
__R_FN_PARAMS_FULL,
|
|
FailureType type,
|
|
const ResultStatus& resultPair,
|
|
_In_opt_ PCWSTR message,
|
|
bool fWantDebugString,
|
|
_Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString,
|
|
_Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars,
|
|
_Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString,
|
|
_Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars,
|
|
_Out_ FailureInfo* failure) WI_NOEXCEPT;
|
|
|
|
__declspec(noinline) inline void ReportFailure(
|
|
__R_FN_PARAMS_FULL,
|
|
FailureType type,
|
|
const ResultStatus& resultPair,
|
|
_In_opt_ PCWSTR message = nullptr,
|
|
ReportFailureOptions options = ReportFailureOptions::None);
|
|
template <FailureType, bool = false>
|
|
__declspec(noinline) inline void ReportFailure_Base(
|
|
__R_FN_PARAMS_FULL,
|
|
const ResultStatus& resultPair,
|
|
_In_opt_ PCWSTR message = nullptr,
|
|
ReportFailureOptions options = ReportFailureOptions::None);
|
|
template <FailureType>
|
|
inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...);
|
|
__declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr);
|
|
template <FailureType>
|
|
__declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr);
|
|
template <FailureType>
|
|
__declspec(noinline) inline HRESULT
|
|
ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
|
|
|
|
//*****************************************************************************
|
|
// Fail fast helpers (for use only internally to WIL)
|
|
//*****************************************************************************
|
|
|
|
/// @cond
|
|
#define __FAIL_FAST_ASSERT__(condition) \
|
|
do \
|
|
{ \
|
|
if (!(condition)) \
|
|
{ \
|
|
__RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __FAIL_FAST_IMMEDIATE_ASSERT__(condition) \
|
|
do \
|
|
{ \
|
|
if (!(condition)) \
|
|
{ \
|
|
wil::FailureInfo failure{}; \
|
|
wil::details::WilFailFast(failure); \
|
|
} \
|
|
} while ((void)0, 0)
|
|
#define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition) \
|
|
__RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#condition) wil::verify_BOOL(condition))
|
|
|
|
// A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages
|
|
// an allocated buffer and maintains the size.
|
|
|
|
class shared_buffer
|
|
{
|
|
public:
|
|
shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0)
|
|
{
|
|
}
|
|
|
|
shared_buffer(shared_buffer const& other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0)
|
|
{
|
|
assign(other.m_pCopy, other.m_size);
|
|
}
|
|
|
|
shared_buffer(shared_buffer&& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy), m_size(other.m_size)
|
|
{
|
|
other.m_pCopy = nullptr;
|
|
other.m_size = 0;
|
|
}
|
|
|
|
~shared_buffer() WI_NOEXCEPT
|
|
{
|
|
reset();
|
|
}
|
|
|
|
shared_buffer& operator=(shared_buffer const& other) WI_NOEXCEPT
|
|
{
|
|
if (this != wistd::addressof(other))
|
|
{
|
|
assign(other.m_pCopy, other.m_size);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
shared_buffer& operator=(shared_buffer&& other) WI_NOEXCEPT
|
|
{
|
|
if (this != wistd::addressof(other))
|
|
{
|
|
reset();
|
|
m_pCopy = other.m_pCopy;
|
|
m_size = other.m_size;
|
|
other.m_pCopy = nullptr;
|
|
other.m_size = 0;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void reset() WI_NOEXCEPT
|
|
{
|
|
if (m_pCopy != nullptr)
|
|
{
|
|
if (0 == ::InterlockedDecrementRelease(m_pCopy))
|
|
{
|
|
WIL_FreeMemory(m_pCopy);
|
|
}
|
|
m_pCopy = nullptr;
|
|
m_size = 0;
|
|
}
|
|
}
|
|
|
|
bool create(_In_reads_bytes_opt_(cbData) void const* pData, size_t cbData) WI_NOEXCEPT
|
|
{
|
|
if (cbData == 0)
|
|
{
|
|
reset();
|
|
return true;
|
|
}
|
|
|
|
long* pCopyRefCount = reinterpret_cast<long*>(WIL_AllocateMemory(sizeof(long) + cbData));
|
|
if (pCopyRefCount == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
*pCopyRefCount = 0;
|
|
if (pData != nullptr)
|
|
{
|
|
memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter
|
|
}
|
|
assign(pCopyRefCount, cbData);
|
|
return true;
|
|
}
|
|
|
|
bool create(size_t cbData) WI_NOEXCEPT
|
|
{
|
|
return create(nullptr, cbData);
|
|
}
|
|
|
|
WI_NODISCARD void* get(_Out_opt_ size_t* pSize = nullptr) const WI_NOEXCEPT
|
|
{
|
|
if (pSize != nullptr)
|
|
{
|
|
*pSize = m_size;
|
|
}
|
|
return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1);
|
|
}
|
|
|
|
WI_NODISCARD size_t size() const WI_NOEXCEPT
|
|
{
|
|
return m_size;
|
|
}
|
|
|
|
WI_NODISCARD explicit operator bool() const WI_NOEXCEPT
|
|
{
|
|
return (m_pCopy != nullptr);
|
|
}
|
|
|
|
WI_NODISCARD bool unique() const WI_NOEXCEPT
|
|
{
|
|
return ((m_pCopy != nullptr) && (*m_pCopy == 1));
|
|
}
|
|
|
|
private:
|
|
long* m_pCopy; // pointer to allocation: refcount + data
|
|
size_t m_size; // size of the data from m_pCopy
|
|
|
|
void assign(_In_opt_ long* pCopy, size_t cbSize) WI_NOEXCEPT
|
|
{
|
|
reset();
|
|
if (pCopy != nullptr)
|
|
{
|
|
m_pCopy = pCopy;
|
|
m_size = cbSize;
|
|
::InterlockedIncrementNoFence(m_pCopy);
|
|
}
|
|
}
|
|
};
|
|
|
|
inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void* pData, size_t countBytes) WI_NOEXCEPT
|
|
{
|
|
shared_buffer buffer;
|
|
buffer.create(pData, countBytes);
|
|
return buffer;
|
|
}
|
|
|
|
inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT
|
|
{
|
|
shared_buffer buffer;
|
|
buffer.create(countBytes);
|
|
return buffer;
|
|
}
|
|
|
|
// A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is
|
|
// always simply contained within (it cannot be attached or detached).
|
|
|
|
template <typename object_t>
|
|
class shared_object
|
|
{
|
|
public:
|
|
shared_object() WI_NOEXCEPT : m_pCopy(nullptr)
|
|
{
|
|
}
|
|
|
|
shared_object(shared_object const& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy)
|
|
{
|
|
if (m_pCopy != nullptr)
|
|
{
|
|
::InterlockedIncrementNoFence(&m_pCopy->m_refCount);
|
|
}
|
|
}
|
|
|
|
shared_object(shared_object&& other) WI_NOEXCEPT : m_pCopy(other.m_pCopy)
|
|
{
|
|
other.m_pCopy = nullptr;
|
|
}
|
|
|
|
~shared_object() WI_NOEXCEPT
|
|
{
|
|
reset();
|
|
}
|
|
|
|
shared_object& operator=(shared_object const& other) WI_NOEXCEPT
|
|
{
|
|
if (this != wistd::addressof(other))
|
|
{
|
|
reset();
|
|
m_pCopy = other.m_pCopy;
|
|
if (m_pCopy != nullptr)
|
|
{
|
|
::InterlockedIncrementNoFence(&m_pCopy->m_refCount);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
shared_object& operator=(shared_object&& other) WI_NOEXCEPT
|
|
{
|
|
if (this != wistd::addressof(other))
|
|
{
|
|
reset();
|
|
m_pCopy = other.m_pCopy;
|
|
other.m_pCopy = nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void reset() WI_NOEXCEPT
|
|
{
|
|
if (m_pCopy != nullptr)
|
|
{
|
|
if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount))
|
|
{
|
|
delete m_pCopy;
|
|
}
|
|
m_pCopy = nullptr;
|
|
}
|
|
}
|
|
|
|
bool create()
|
|
{
|
|
RefAndObject* pObject = new (std::nothrow) RefAndObject();
|
|
if (pObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
reset();
|
|
m_pCopy = pObject;
|
|
return true;
|
|
}
|
|
|
|
template <typename param_t>
|
|
bool create(param_t&& param1)
|
|
{
|
|
RefAndObject* pObject = new (std::nothrow) RefAndObject(wistd::forward<param_t>(param1));
|
|
if (pObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
reset();
|
|
m_pCopy = pObject;
|
|
return true;
|
|
}
|
|
|
|
WI_NODISCARD object_t* get() const WI_NOEXCEPT
|
|
{
|
|
return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object;
|
|
}
|
|
|
|
WI_NODISCARD explicit operator bool() const WI_NOEXCEPT
|
|
{
|
|
return (m_pCopy != nullptr);
|
|
}
|
|
|
|
WI_NODISCARD bool unique() const WI_NOEXCEPT
|
|
{
|
|
return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1));
|
|
}
|
|
|
|
WI_NODISCARD object_t* operator->() const WI_NOEXCEPT
|
|
{
|
|
return get();
|
|
}
|
|
|
|
private:
|
|
struct RefAndObject
|
|
{
|
|
long m_refCount;
|
|
object_t m_object;
|
|
|
|
RefAndObject() : m_refCount(1), m_object()
|
|
{
|
|
}
|
|
|
|
template <typename param_t>
|
|
RefAndObject(param_t&& param1) : m_refCount(1), m_object(wistd::forward<param_t>(param1))
|
|
{
|
|
}
|
|
};
|
|
|
|
RefAndObject* m_pCopy;
|
|
};
|
|
|
|
// The following functions are basically the same, but are kept separated to:
|
|
// 1) Provide a unique count and last error code per-type
|
|
// 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based
|
|
// upon count of errors from a particular type, etc)
|
|
__WI_PUSH_WARNINGS
|
|
#if __clang_major__ >= 13
|
|
__WI_CLANG_DISABLE_WARNING(-Wunused-but-set-variable) // s_hrErrorLast used for debugging. We intentionally only assign to it
|
|
#endif
|
|
__declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
static HRESULT volatile s_hrErrorLast = S_OK;
|
|
static long volatile s_cErrorCount = 0;
|
|
s_hrErrorLast = hr;
|
|
return ::InterlockedIncrementNoFence(&s_cErrorCount);
|
|
}
|
|
|
|
__declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
static HRESULT volatile s_hrErrorLast = S_OK;
|
|
static long volatile s_cErrorCount = 0;
|
|
s_hrErrorLast = hr;
|
|
return ::InterlockedIncrementNoFence(&s_cErrorCount);
|
|
}
|
|
|
|
__declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
static HRESULT volatile s_hrErrorLast = S_OK;
|
|
static long volatile s_cErrorCount = 0;
|
|
s_hrErrorLast = hr;
|
|
return ::InterlockedIncrementNoFence(&s_cErrorCount);
|
|
}
|
|
|
|
__declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
static HRESULT volatile s_hrErrorLast = S_OK;
|
|
s_hrErrorLast = hr;
|
|
return 1;
|
|
}
|
|
__WI_POP_WARNINGS
|
|
|
|
inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags)
|
|
{
|
|
// if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.)
|
|
// or via direct linkage (e.g. UWP apps), then use it.
|
|
if (g_pfnRaiseFailFastException)
|
|
{
|
|
g_pfnRaiseFailFastException(er, cr, flags);
|
|
}
|
|
// if not, as a best effort, we are just going to call the intrinsic.
|
|
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
|
}
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
|
inline bool __stdcall GetModuleInformation(
|
|
_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_NOEXCEPT
|
|
{
|
|
HMODULE hModule = nullptr;
|
|
if (address && !GetModuleHandleExW(
|
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
|
reinterpret_cast<PCWSTR>(address),
|
|
&hModule))
|
|
{
|
|
assign_to_opt_param(addressOffset, 0U);
|
|
return false;
|
|
}
|
|
if (addressOffset)
|
|
{
|
|
*addressOffset =
|
|
address ? static_cast<unsigned int>(static_cast<unsigned char*>(address) - reinterpret_cast<unsigned char*>(hModule))
|
|
: 0;
|
|
}
|
|
if (name)
|
|
{
|
|
char modulePath[MAX_PATH];
|
|
if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PCSTR start = modulePath + strlen(modulePath);
|
|
while ((start > modulePath) && (*(start - 1) != '\\'))
|
|
{
|
|
start--;
|
|
}
|
|
StringCchCopyA(name, size, start);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT
|
|
{
|
|
static char s_szModule[64] = {};
|
|
static volatile bool s_fModuleValid = false;
|
|
if (!s_fModuleValid) // Races are acceptable
|
|
{
|
|
GetModuleInformation(reinterpret_cast<void*>(&RecordFailFast), nullptr, s_szModule, ARRAYSIZE(s_szModule));
|
|
s_fModuleValid = true;
|
|
}
|
|
return s_szModule;
|
|
}
|
|
|
|
inline void __stdcall DebugBreak() WI_NOEXCEPT
|
|
{
|
|
::DebugBreak();
|
|
}
|
|
|
|
inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags)
|
|
{
|
|
auto k32handle = GetModuleHandleW(L"kernelbase.dll");
|
|
_Analysis_assume_(k32handle != nullptr);
|
|
auto pfnRaiseFailFastException =
|
|
reinterpret_cast<decltype(WilDynamicLoadRaiseFailFastException)*>(GetProcAddress(k32handle, "RaiseFailFastException"));
|
|
if (pfnRaiseFailFastException)
|
|
{
|
|
pfnRaiseFailFastException(er, cr, flags);
|
|
}
|
|
}
|
|
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
|
|
|
inline bool __stdcall GetModuleInformationFromAddress(
|
|
_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* buffer, size_t size) WI_NOEXCEPT
|
|
{
|
|
if (size > 0)
|
|
{
|
|
assign_to_opt_param(buffer, '\0');
|
|
}
|
|
if (addressOffset)
|
|
{
|
|
*addressOffset = 0;
|
|
}
|
|
if (g_pfnGetModuleInformation)
|
|
{
|
|
return g_pfnGetModuleInformation(address, addressOffset, buffer, size);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
__declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
// The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb
|
|
if (SUCCEEDED_NTSTATUS(status))
|
|
{
|
|
// All successful status codes have only one hresult equivalent, S_OK
|
|
return S_OK;
|
|
}
|
|
if (status == static_cast<NTSTATUS>(STATUS_NO_MEMORY))
|
|
{
|
|
// RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr)
|
|
{
|
|
DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status);
|
|
|
|
// ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to the Win32 error codes).
|
|
// There are known instances of this bug which are unlikely to be fixed soon, and it's always possible that additional instances
|
|
// could be added in the future. In these cases, it's better to use HRESULT_FROM_NT rather than returning a meaningless error.
|
|
if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND))
|
|
{
|
|
return __HRESULT_FROM_WIN32(err);
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_NT(status);
|
|
}
|
|
|
|
__declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
// Constants taken from ntstatus.h
|
|
static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = 0xC000000D;
|
|
static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = 0xC00000E5;
|
|
static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = 0xC0000095;
|
|
static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A;
|
|
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
|
|
static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = 0xC0000002;
|
|
static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = 0x80000005;
|
|
static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B;
|
|
static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = 0xC0000273;
|
|
static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = 0xC0000161;
|
|
static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = 0xC0000163;
|
|
static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = 0xC0000023;
|
|
static constexpr NTSTATUS WIL_STATUS_DISK_FULL = 0xC000007F;
|
|
static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = 0xC0000033;
|
|
static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = 0xC0000135;
|
|
static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = 0xC0000059;
|
|
static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = 0xC000A083;
|
|
static constexpr HRESULT WIL_E_FAIL = 0x80004005;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
case E_INVALIDARG:
|
|
status = WIL_STATUS_INVALID_PARAMETER;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR):
|
|
status = WIL_STATUS_INTERNAL_ERROR;
|
|
break;
|
|
case E_OUTOFMEMORY:
|
|
status = STATUS_NO_MEMORY;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW):
|
|
status = WIL_STATUS_INTEGER_OVERFLOW;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
|
|
status = WIL_STATUS_OBJECT_PATH_NOT_FOUND;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
|
|
status = WIL_STATUS_OBJECT_NAME_NOT_FOUND;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION):
|
|
status = WIL_STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_MORE_DATA):
|
|
status = WIL_STATUS_BUFFER_OVERFLOW;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_IMPLEMENTATION_LIMIT):
|
|
status = WIL_STATUS_IMPLEMENTATION_LIMIT;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_NO_MORE_MATCHES):
|
|
status = WIL_STATUS_NO_MORE_MATCHES;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_ILLEGAL_CHARACTER):
|
|
status = WIL_STATUS_ILLEGAL_CHARACTER;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_UNDEFINED_CHARACTER):
|
|
status = WIL_STATUS_UNDEFINED_CHARACTER;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER):
|
|
status = WIL_STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_DISK_FULL):
|
|
status = WIL_STATUS_DISK_FULL;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_INVALID_NAME):
|
|
status = WIL_STATUS_OBJECT_NAME_INVALID;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND):
|
|
status = WIL_STATUS_DLL_NOT_FOUND;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION):
|
|
status = WIL_STATUS_REVISION_MISMATCH;
|
|
break;
|
|
case WIL_E_FAIL:
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_XML_PARSE_ERROR):
|
|
status = WIL_STATUS_XML_PARSE_ERROR;
|
|
break;
|
|
case __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION):
|
|
status = STATUS_NONCONTINUABLE_EXCEPTION;
|
|
break;
|
|
default:
|
|
if ((hr & FACILITY_NT_BIT) != 0)
|
|
{
|
|
status = (hr & ~FACILITY_NT_BIT);
|
|
}
|
|
else if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
|
{
|
|
status = __NTSTATUS_FROM_WIN32(HRESULT_CODE(hr));
|
|
}
|
|
else if (HRESULT_FACILITY(hr) == FACILITY_SSPI)
|
|
{
|
|
status =
|
|
((NTSTATUS)(hr) <= 0 ? ((NTSTATUS)(hr))
|
|
: ((NTSTATUS)(((hr)&0x0000FFFF) | (FACILITY_SSPI << 16) | ERROR_SEVERITY_ERROR)));
|
|
}
|
|
else
|
|
{
|
|
status = WIL_STATUS_INTERNAL_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// The following set of functions all differ only based upon number of arguments. They are unified in their handling
|
|
// of data from each of the various error-handling types (fast fail, exceptions, etc.).
|
|
_Post_equals_last_error_ inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT
|
|
{
|
|
__R_FN_UNREFERENCED;
|
|
auto err = ::GetLastError();
|
|
if (SUCCEEDED_WIN32(err))
|
|
{
|
|
// This function should only be called when GetLastError() is set to a FAILURE.
|
|
// If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues:
|
|
// 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually
|
|
// set the last error (consult MSDN).
|
|
// 2) Your macro check against the error is not immediately after the API call. Pushing it later can result
|
|
// in another API call between the previous one and the check resetting the last error.
|
|
// 3) The API you're calling has a bug in it and does not accurately set the last error (there are a few
|
|
// examples here, such as SendMessageTimeout() that don't accurately set the last error).
|
|
// [MSFT internal] For these, please send mail to 'wildisc' when found and work-around with win32errorhelpers.
|
|
|
|
WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. GetLastError() does not have an error.");
|
|
return ERROR_ASSERTION_FAILURE;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS_FULL_RA;
|
|
return GetLastErrorFail(__R_FN_CALL_FULL);
|
|
}
|
|
|
|
_Translates_last_error_to_HRESULT_
|
|
inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL));
|
|
}
|
|
|
|
_Translates_last_error_to_HRESULT_
|
|
inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS_FULL_RA;
|
|
return GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
}
|
|
|
|
inline void PrintLoggingMessage(
|
|
_Out_writes_(cchDest) _Post_z_ PWSTR pszDest,
|
|
_Pre_satisfies_(cchDest > 0) size_t cchDest,
|
|
_In_opt_ _Printf_format_string_ PCSTR formatString,
|
|
_In_opt_ va_list argList) WI_NOEXCEPT
|
|
{
|
|
if (formatString == nullptr)
|
|
{
|
|
pszDest[0] = L'\0';
|
|
}
|
|
else if (argList == nullptr)
|
|
{
|
|
StringCchPrintfW(pszDest, cchDest, L"%hs", formatString);
|
|
}
|
|
else
|
|
{
|
|
wchar_t szFormatWide[2048];
|
|
StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString);
|
|
StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList);
|
|
}
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : __WARNING_RETURNING_BAD_RESULT)
|
|
// NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using
|
|
// Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled).
|
|
|
|
static STRSAFEAPI WilStringLengthWorkerA(
|
|
_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz,
|
|
_In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
|
|
_Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
size_t cchOriginalMax = cchMax;
|
|
while (cchMax && (*psz != '\0'))
|
|
{
|
|
psz++;
|
|
cchMax--;
|
|
}
|
|
if (cchMax == 0)
|
|
{
|
|
// the string is longer than cchMax
|
|
hr = STRSAFE_E_INVALID_PARAMETER;
|
|
}
|
|
if (pcchLength)
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pcchLength = cchOriginalMax - cchMax;
|
|
}
|
|
else
|
|
{
|
|
*pcchLength = 0;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
STRSAFEAPI StringCchLengthA(
|
|
_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz,
|
|
_In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax,
|
|
_Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if ((psz == nullptr) || (cchMax > STRSAFE_MAX_CCH))
|
|
{
|
|
hr = STRSAFE_E_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
hr = WilStringLengthWorkerA(psz, cchMax, pcchLength);
|
|
}
|
|
if (FAILED(hr) && pcchLength)
|
|
{
|
|
*pcchLength = 0;
|
|
}
|
|
return hr;
|
|
}
|
|
#pragma warning(pop)
|
|
|
|
_Post_satisfies_(cchDest > 0 && cchDest <= cchMax) static STRSAFEAPI
|
|
WilStringValidateDestA(_In_reads_opt_(cchDest) STRSAFE_PCNZCH /*pszDest*/, _In_ size_t cchDest, _In_ const size_t cchMax)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if ((cchDest == 0) || (cchDest > cchMax))
|
|
{
|
|
hr = STRSAFE_E_INVALID_PARAMETER;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
static STRSAFEAPI WilStringVPrintfWorkerA(
|
|
_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
|
|
_In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
|
|
_Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength,
|
|
_In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
|
|
_In_ va_list argList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int iRet{};
|
|
|
|
// leave the last space for the null terminator
|
|
size_t cchMax = cchDest - 1;
|
|
size_t cchNewDestLength = 0;
|
|
#undef STRSAFE_USE_SECURE_CRT
|
|
#define STRSAFE_USE_SECURE_CRT 1
|
|
#if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
|
|
iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList);
|
|
#else
|
|
#pragma warning(push)
|
|
#pragma warning(disable : __WARNING_BANNED_API_USAGE) // "STRSAFE not included"
|
|
iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
|
|
#pragma warning(pop)
|
|
#endif
|
|
// ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
|
|
|
|
if ((iRet < 0) || (((size_t)iRet) > cchMax))
|
|
{
|
|
// need to null terminate the string
|
|
pszDest += cchMax;
|
|
*pszDest = '\0';
|
|
|
|
cchNewDestLength = cchMax;
|
|
|
|
// we have truncated pszDest
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (((size_t)iRet) == cchMax)
|
|
{
|
|
// need to null terminate the string
|
|
pszDest += cchMax;
|
|
*pszDest = '\0';
|
|
|
|
cchNewDestLength = cchMax;
|
|
}
|
|
else
|
|
{
|
|
cchNewDestLength = (size_t)iRet;
|
|
}
|
|
|
|
if (pcchNewDestLength)
|
|
{
|
|
*pcchNewDestLength = cchNewDestLength;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
__inline HRESULT StringCchPrintfA(
|
|
_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
|
|
_In_ size_t cchDest,
|
|
_In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
|
|
...)
|
|
{
|
|
HRESULT hr;
|
|
hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, pszFormat);
|
|
hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, nullptr, pszFormat, argList);
|
|
va_end(argList);
|
|
}
|
|
else if (cchDest > 0)
|
|
{
|
|
*pszDest = '\0';
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char)))
|
|
inline size_t ResultStringSize(_In_opt_ PCSTR psz)
|
|
{
|
|
return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char));
|
|
}
|
|
|
|
_Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t)))
|
|
inline size_t ResultStringSize(_In_opt_ PCWSTR psz)
|
|
{
|
|
return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t);
|
|
}
|
|
|
|
template <typename TString>
|
|
_Ret_range_(pStart, pEnd)
|
|
inline unsigned char* WriteResultString(
|
|
_Pre_satisfies_(pStart <= pEnd) _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_) _When_(
|
|
(pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0),
|
|
_Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) unsigned char* pStart,
|
|
_Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd,
|
|
_In_opt_z_ TString pszString,
|
|
_Outptr_result_maybenull_z_ TString* ppszBufferString)
|
|
{
|
|
// No space? Null string? Do nothing.
|
|
if ((pStart == pEnd) || !pszString || !*pszString)
|
|
{
|
|
assign_null_to_opt_param(ppszBufferString);
|
|
return pStart;
|
|
}
|
|
|
|
// Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to
|
|
// the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough,
|
|
// do nothing, and tell the caller nothing was written.
|
|
size_t const stringSize = ResultStringSize(pszString);
|
|
size_t const bufferSize = pEnd - pStart;
|
|
if (bufferSize < stringSize)
|
|
{
|
|
assign_null_to_opt_param(ppszBufferString);
|
|
return pStart;
|
|
}
|
|
|
|
memcpy_s(pStart, bufferSize, pszString, stringSize);
|
|
assign_to_opt_param(
|
|
ppszBufferString,
|
|
reinterpret_cast<TString>(
|
|
pStart)); // lgtm[cpp/incorrect-string-type-conversion] False positive - The query is misinterpreting a buffer (char *) with a MBS string, the cast to TString is expected.
|
|
return pStart + stringSize;
|
|
}
|
|
|
|
_Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0)
|
|
inline size_t UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax)
|
|
{
|
|
size_t cbLength;
|
|
return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0;
|
|
}
|
|
_Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0)
|
|
inline size_t UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax)
|
|
{
|
|
size_t cbLength;
|
|
return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0;
|
|
}
|
|
|
|
template <typename TString>
|
|
_Ret_range_(pStart, pEnd)
|
|
inline unsigned char* GetResultString(
|
|
_In_reads_to_ptr_opt_(pEnd) unsigned char* pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, _Out_ TString* ppszBufferString)
|
|
{
|
|
size_t cchLen = UntrustedStringLength(reinterpret_cast<TString>(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0]));
|
|
*ppszBufferString = (cchLen > 0) ? reinterpret_cast<TString>(pStart) : nullptr;
|
|
auto pReturn = (wistd::min)(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0])));
|
|
__analysis_assume((pReturn >= pStart) && (pReturn <= pEnd));
|
|
return pReturn;
|
|
}
|
|
} // namespace details
|
|
/// @endcond
|
|
|
|
//*****************************************************************************
|
|
// WIL result handling initializers
|
|
//
|
|
// Generally, callers do not need to manually initialize WIL. This header creates
|
|
// the appropriate .CRT init section pieces through global objects to ensure that
|
|
// WilInitialize... is called before DllMain or main().
|
|
//
|
|
// Certain binaries do not link with the CRT or do not support .CRT-section based
|
|
// initializers. Those binaries must link only with other static libraries that
|
|
// also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left,
|
|
// and they should call one of the WilInitialize_ResultMacros_??? methods during
|
|
// their initialization phase. Skipping this initialization path is OK as well,
|
|
// but results in a slightly degraded experience with result reporting.
|
|
//
|
|
// Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides:
|
|
// - The name of the current module in wil::FailureInfo::pszModule
|
|
// - The name of the returning-to module during wil/staging.h failures
|
|
//*****************************************************************************
|
|
|
|
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
|
//! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. WIL will
|
|
//! only use publicly documented APIs.
|
|
inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse()
|
|
{
|
|
details::g_pfnGetModuleName = details::GetCurrentModuleName;
|
|
details::g_pfnGetModuleInformation = details::GetModuleInformation;
|
|
details::g_pfnDebugBreak = details::DebugBreak;
|
|
details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException;
|
|
}
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS
|
|
#if !defined(BUILD_WINDOWS) || defined(WIL_SUPPRESS_PRIVATE_API_USE)
|
|
WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, [] {
|
|
::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse();
|
|
return 1;
|
|
});
|
|
#endif
|
|
#endif
|
|
} // namespace details
|
|
/// @endcond
|
|
#else // !WINAPI_PARTITION_DESKTOP, !WINAPI_PARTITION_SYSTEM, explicitly assume these modules can direct link
|
|
namespace details
|
|
{
|
|
WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, [] {
|
|
g_pfnRaiseFailFastException = ::RaiseFailFastException;
|
|
return 1;
|
|
});
|
|
}
|
|
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
|
|
|
|
//*****************************************************************************
|
|
// Public Error Handling Helpers
|
|
//*****************************************************************************
|
|
|
|
//! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload).
|
|
inline bool ProcessShutdownInProgress()
|
|
{
|
|
return (details::g_processShutdownInProgress || (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false));
|
|
}
|
|
|
|
/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down,
|
|
but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll). The hosting DLL is responsible for calling
|
|
Construct() and Destroy() to manually run the constructor and destructor during DLL load & unload.
|
|
Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is
|
|
called as is typical. */
|
|
template <class T>
|
|
class manually_managed_shutdown_aware_object
|
|
{
|
|
public:
|
|
manually_managed_shutdown_aware_object() = default;
|
|
manually_managed_shutdown_aware_object(manually_managed_shutdown_aware_object const&) = delete;
|
|
void operator=(manually_managed_shutdown_aware_object const&) = delete;
|
|
|
|
void construct()
|
|
{
|
|
void* var = &m_raw;
|
|
::new (var) T();
|
|
}
|
|
|
|
void destroy()
|
|
{
|
|
if (ProcessShutdownInProgress())
|
|
{
|
|
get().ProcessShutdown();
|
|
}
|
|
else
|
|
{
|
|
(&get())->~T();
|
|
}
|
|
}
|
|
|
|
//! Retrieves a reference to the contained object
|
|
T& get() WI_NOEXCEPT
|
|
{
|
|
return *reinterpret_cast<T*>(&m_raw);
|
|
}
|
|
|
|
private:
|
|
alignas(T) unsigned char m_raw[sizeof(T)];
|
|
};
|
|
|
|
/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down.
|
|
Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is
|
|
called as is typical. */
|
|
template <class T>
|
|
class shutdown_aware_object
|
|
{
|
|
public:
|
|
shutdown_aware_object()
|
|
{
|
|
m_object.construct();
|
|
}
|
|
|
|
~shutdown_aware_object()
|
|
{
|
|
m_object.destroy();
|
|
}
|
|
|
|
shutdown_aware_object(shutdown_aware_object const&) = delete;
|
|
void operator=(shutdown_aware_object const&) = delete;
|
|
|
|
//! Retrieves a reference to the contained object
|
|
T& get() WI_NOEXCEPT
|
|
{
|
|
return m_object.get();
|
|
}
|
|
|
|
private:
|
|
manually_managed_shutdown_aware_object<T> m_object;
|
|
};
|
|
|
|
/** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. */
|
|
template <class T>
|
|
class object_without_destructor_on_shutdown
|
|
{
|
|
public:
|
|
object_without_destructor_on_shutdown()
|
|
{
|
|
void* var = &m_raw;
|
|
::new (var) T();
|
|
}
|
|
|
|
~object_without_destructor_on_shutdown()
|
|
{
|
|
if (!ProcessShutdownInProgress())
|
|
{
|
|
get().~T();
|
|
}
|
|
}
|
|
|
|
object_without_destructor_on_shutdown(object_without_destructor_on_shutdown const&) = delete;
|
|
void operator=(object_without_destructor_on_shutdown const&) = delete;
|
|
|
|
//! Retrieves a reference to the contained object
|
|
T& get() WI_NOEXCEPT
|
|
{
|
|
return *reinterpret_cast<T*>(&m_raw);
|
|
}
|
|
|
|
private:
|
|
alignas(T) unsigned char m_raw[sizeof(T)]{};
|
|
};
|
|
|
|
/** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because
|
|
of termination or normal unload. Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this
|
|
determination on its own without this callback. Suppressing private APIs requires use of this. */
|
|
inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved)
|
|
{
|
|
if (!details::g_processShutdownInProgress)
|
|
{
|
|
if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr))
|
|
{
|
|
details::g_processShutdownInProgress = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// [optionally] Plug in fallback telemetry reporting
|
|
// Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module
|
|
// could re-route fallback telemetry to any ONE specific provider by calling this method.
|
|
inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction)
|
|
{
|
|
// Only ONE telemetry provider can own the fallback telemetry callback.
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) ||
|
|
(details::g_pfnTelemetryCallback == callbackFunction));
|
|
details::g_pfnTelemetryCallback = callbackFunction;
|
|
}
|
|
|
|
// [optionally] Plug in result logging (do not use for telemetry)
|
|
// This provides the ability for a module to hook all failures flowing through the system for inspection
|
|
// and/or logging.
|
|
inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction)
|
|
{
|
|
// Only ONE function can own the result logging callback
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) ||
|
|
(details::g_pfnLoggingCallback == callbackFunction));
|
|
details::g_pfnLoggingCallback = callbackFunction;
|
|
}
|
|
|
|
// [optionally] Plug in custom result messages
|
|
// There are some purposes that require translating the full information that is known about a failure
|
|
// into a message to be logged (either through the console for debugging OR as the message attached
|
|
// to a Platform::Exception^). This callback allows a module to format the string itself away from the
|
|
// default.
|
|
inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction)
|
|
{
|
|
// Only ONE function can own the result message callback
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || (g_pfnResultLoggingCallback == callbackFunction));
|
|
details::g_resultMessageCallbackSet = true;
|
|
g_pfnResultLoggingCallback = callbackFunction;
|
|
}
|
|
|
|
// [optionally] Plug in exception remapping
|
|
// A module can plug a callback in using this function to setup custom exception handling to allow any
|
|
// exception type to be converted into an HRESULT from exception barriers.
|
|
inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction)
|
|
{
|
|
// Only ONE function can own the exception conversion
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) ||
|
|
(g_pfnResultFromCaughtException == callbackFunction));
|
|
g_pfnResultFromCaughtException = callbackFunction;
|
|
}
|
|
|
|
// [optionally] Plug in exception remapping
|
|
// This provides the ability for a module to call RoOriginateError in case of a failure.
|
|
// Normally, the callback is owned by including result_originate.h in the including module. Alternatively a module
|
|
// could re-route error origination callback to its own implementation.
|
|
inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction)
|
|
{
|
|
// Only ONE function can own the error origination callback
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) ||
|
|
(details::g_pfnOriginateCallback == callbackFunction));
|
|
details::g_pfnOriginateCallback = callbackFunction;
|
|
}
|
|
|
|
// [optionally] Plug in failfast callback
|
|
// This provides the ability for a module to call RoFailFastWithErrorContext in the failfast handler -if- there is stowed
|
|
// exception data available. Normally, the callback is owned by including result_originate.h in the including module.
|
|
// Alternatively a module could re-route to its own implementation.
|
|
inline void SetFailfastWithContextCallback(_In_opt_ decltype(details::g_pfnFailfastWithContextCallback) callbackFunction)
|
|
{
|
|
// Only ONE function can own the failfast with context callback
|
|
__FAIL_FAST_IMMEDIATE_ASSERT__(
|
|
(details::g_pfnFailfastWithContextCallback == nullptr) || (callbackFunction == nullptr) ||
|
|
(details::g_pfnFailfastWithContextCallback == callbackFunction));
|
|
details::g_pfnFailfastWithContextCallback = callbackFunction;
|
|
}
|
|
|
|
// A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed
|
|
// on the stack or from the caller). The storage of FailureInfo needs to copy some data internally
|
|
// for lifetime purposes.
|
|
|
|
class StoredFailureInfo
|
|
{
|
|
public:
|
|
StoredFailureInfo() WI_NOEXCEPT
|
|
{
|
|
::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo));
|
|
}
|
|
|
|
StoredFailureInfo(FailureInfo const& other) WI_NOEXCEPT
|
|
{
|
|
SetFailureInfo(other);
|
|
}
|
|
|
|
WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT
|
|
{
|
|
return m_failureInfo;
|
|
}
|
|
|
|
void SetFailureInfo(FailureInfo const& failure) WI_NOEXCEPT
|
|
{
|
|
m_failureInfo = failure;
|
|
|
|
size_t const cbNeed = details::ResultStringSize(failure.pszMessage) + details::ResultStringSize(failure.pszCode) +
|
|
details::ResultStringSize(failure.pszFunction) + details::ResultStringSize(failure.pszFile) +
|
|
details::ResultStringSize(failure.pszCallContext) + details::ResultStringSize(failure.pszModule) +
|
|
details::ResultStringSize(failure.callContextCurrent.contextName) +
|
|
details::ResultStringSize(failure.callContextCurrent.contextMessage) +
|
|
details::ResultStringSize(failure.callContextOriginating.contextName) +
|
|
details::ResultStringSize(failure.callContextOriginating.contextMessage);
|
|
|
|
if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed))
|
|
{
|
|
m_spStrings.reset();
|
|
m_spStrings.create(cbNeed);
|
|
}
|
|
|
|
size_t cbAlloc;
|
|
unsigned char* pBuffer = static_cast<unsigned char*>(m_spStrings.get(&cbAlloc));
|
|
unsigned char* pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr;
|
|
|
|
if (pBuffer)
|
|
{
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage);
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode);
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction);
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile);
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext);
|
|
pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule);
|
|
pBuffer = details::WriteResultString(
|
|
pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName);
|
|
pBuffer = details::WriteResultString(
|
|
pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage);
|
|
pBuffer = details::WriteResultString(
|
|
pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName);
|
|
pBuffer = details::WriteResultString(
|
|
pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage);
|
|
ZeroMemory(pBuffer, pBufferEnd - pBuffer);
|
|
}
|
|
}
|
|
|
|
// Relies upon generated copy constructor and assignment operator
|
|
|
|
protected:
|
|
FailureInfo m_failureInfo;
|
|
details::shared_buffer m_spStrings;
|
|
};
|
|
|
|
#if defined(WIL_ENABLE_EXCEPTIONS) || defined(WIL_FORCE_INCLUDE_RESULT_EXCEPTION)
|
|
|
|
//! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx).
|
|
//! This class stores all of the FailureInfo context that is available when the exception is thrown. It's also caught by
|
|
//! exception guards for automatic conversion to HRESULT.
|
|
//!
|
|
//! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException has been
|
|
//! changed).
|
|
class ResultException : public std::exception
|
|
{
|
|
public:
|
|
//! Constructs a new ResultException from an existing FailureInfo.
|
|
ResultException(const FailureInfo& failure) WI_NOEXCEPT : m_failure(failure)
|
|
{
|
|
}
|
|
|
|
//! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types).
|
|
ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : m_failure(CustomExceptionFailureInfo(hr))
|
|
{
|
|
}
|
|
|
|
//! Returns the failed HRESULT that this exception represents.
|
|
_Always_(_Post_satisfies_(return < 0)) WI_NODISCARD HRESULT GetErrorCode() const WI_NOEXCEPT
|
|
{
|
|
HRESULT const hr = m_failure.GetFailureInfo().hr;
|
|
__analysis_assume(hr < 0);
|
|
return hr;
|
|
}
|
|
|
|
//! Returns the failed NTSTATUS that this exception represents.
|
|
_Always_(_Post_satisfies_(return < 0)) WI_NODISCARD NTSTATUS GetStatusCode() const WI_NOEXCEPT
|
|
{
|
|
NTSTATUS const status = m_failure.GetFailureInfo().status;
|
|
__analysis_assume(status < 0);
|
|
return status;
|
|
}
|
|
|
|
//! Get a reference to the stored FailureInfo.
|
|
WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT
|
|
{
|
|
return m_failure.GetFailureInfo();
|
|
}
|
|
|
|
//! Sets the stored FailureInfo (use primarily only when constructing custom exception types).
|
|
void SetFailureInfo(FailureInfo const& failure) WI_NOEXCEPT
|
|
{
|
|
m_failure.SetFailureInfo(failure);
|
|
}
|
|
|
|
//! Provides a string representing the FailureInfo from this exception.
|
|
WI_NODISCARD inline const char* __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override
|
|
{
|
|
#if !defined(NONLS) && !defined(NOAPISET)
|
|
if (!m_what)
|
|
{
|
|
wchar_t message[2048];
|
|
GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo());
|
|
|
|
int len = WideCharToMultiByte(CP_ACP, 0, message, -1, nullptr, 0, nullptr, nullptr);
|
|
if (!m_what.create(len))
|
|
{
|
|
// Allocation failed, return placeholder string.
|
|
return "WIL Exception";
|
|
}
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, message, -1, static_cast<char*>(m_what.get()), len, nullptr, nullptr);
|
|
}
|
|
return static_cast<const char*>(m_what.get());
|
|
#else
|
|
if (!m_what)
|
|
{
|
|
wchar_t message[2048];
|
|
GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo());
|
|
|
|
char messageA[1024];
|
|
wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message);
|
|
m_what.create(messageA, strlen(messageA) + sizeof(*messageA));
|
|
}
|
|
return static_cast<const char*>(m_what.get());
|
|
#endif
|
|
}
|
|
|
|
// Relies upon auto-generated copy constructor and assignment operator
|
|
protected:
|
|
StoredFailureInfo m_failure; //!< The failure information for this exception
|
|
mutable details::shared_buffer m_what; //!< The on-demand generated what() string
|
|
|
|
//! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types).
|
|
static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
FailureInfo fi = {};
|
|
fi.type = FailureType::Exception;
|
|
fi.hr = hr;
|
|
return fi;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
// Public Helpers that catch -- mostly only enabled when exceptions are enabled
|
|
//*****************************************************************************
|
|
|
|
// ResultFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally
|
|
// it re-throws and catches the exception to convert it to an HRESULT. If an exception is of an unrecognized type
|
|
// the function will fail fast.
|
|
//
|
|
// try
|
|
// {
|
|
// // Code
|
|
// }
|
|
// catch (...)
|
|
// {
|
|
// hr = wil::ResultFromCaughtException();
|
|
// }
|
|
_Always_(_Post_satisfies_(return < 0)) __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT
|
|
{
|
|
bool isNormalized = false;
|
|
HRESULT hr = S_OK;
|
|
if (details::g_pfnResultFromCaughtExceptionInternal)
|
|
{
|
|
hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).hr;
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Caller bug: an unknown exception was thrown
|
|
__WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions);
|
|
return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
|
}
|
|
|
|
//! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running under an
|
|
//! exception context
|
|
inline void RethrowCaughtException()
|
|
{
|
|
// We always want to rethrow the exception under normal circumstances. Ordinarily, we could actually guarantee
|
|
// this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running
|
|
// dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the
|
|
// runtime check without the noreturn annotation.
|
|
|
|
if (details::g_pfnRethrow)
|
|
{
|
|
details::g_pfnRethrow();
|
|
}
|
|
}
|
|
|
|
//! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code
|
|
inline void ThrowResultException(const FailureInfo& failure)
|
|
{
|
|
if (details::g_pfnThrowResultException)
|
|
{
|
|
details::g_pfnThrowResultException(failure);
|
|
}
|
|
}
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
//*****************************************************************************
|
|
// Private helpers to catch and propagate exceptions
|
|
//*****************************************************************************
|
|
|
|
RESULT_NORETURN inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS)
|
|
{
|
|
// This is an intentional fail-fast that was caught by an exception guard with WIL. Look back up the callstack to
|
|
// determine the source of the actual exception being thrown. The exception guard used by the calling code did not expect
|
|
// this exception type to be thrown or is specifically requesting fail-fast for this class of exception.
|
|
|
|
FailureInfo failure{};
|
|
WilFailFast(failure);
|
|
}
|
|
|
|
inline void MaybeGetExceptionString(
|
|
const ResultException& exception,
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
|
|
{
|
|
if (debugString)
|
|
{
|
|
GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo());
|
|
}
|
|
}
|
|
|
|
inline void MaybeGetExceptionString(
|
|
const std::exception& exception,
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
|
|
{
|
|
if (debugString)
|
|
{
|
|
StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what());
|
|
}
|
|
}
|
|
|
|
inline HRESULT ResultFromKnownException(const ResultException& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
|
|
{
|
|
wchar_t message[2048]{};
|
|
MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
|
|
auto hr = exception.GetErrorCode();
|
|
wil::details::ReportFailure_Base<FailureType::Log>(
|
|
__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message);
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
|
|
{
|
|
wchar_t message[2048]{};
|
|
MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
|
|
constexpr auto hr = E_OUTOFMEMORY;
|
|
wil::details::ReportFailure_Base<FailureType::Log>(
|
|
__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message);
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
|
|
{
|
|
wchar_t message[2048]{};
|
|
MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
|
|
constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
|
ReportFailure_Base<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message);
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress)
|
|
{
|
|
if (g_pfnResultFromCaughtException_CppWinRt)
|
|
{
|
|
wchar_t message[2048]{};
|
|
bool ignored;
|
|
auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored);
|
|
if (FAILED(hr))
|
|
{
|
|
ReportFailure_Base<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success
|
|
return S_OK;
|
|
}
|
|
|
|
inline HRESULT RecognizeCaughtExceptionFromCallback(
|
|
_Inout_updates_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
|
|
{
|
|
HRESULT hr = g_pfnResultFromCaughtException();
|
|
|
|
// If we still don't know the error -- or we would like to get the debug string for the error (if possible) we
|
|
// rethrow and catch std::exception.
|
|
|
|
if (SUCCEEDED(hr) || debugString)
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (std::exception& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
// Fall through to returning 'hr' below
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// clang-format off
|
|
#ifdef __cplusplus_winrt
|
|
inline Platform::String^ GetPlatformExceptionMessage(Platform::Exception^ exception)
|
|
{
|
|
struct RawExceptionData_Partial
|
|
{
|
|
PCWSTR description;
|
|
PCWSTR restrictedErrorString;
|
|
};
|
|
|
|
auto exceptionPtr = reinterpret_cast<void*>(static_cast<::Platform::Object^>(exception));
|
|
auto exceptionInfoPtr = reinterpret_cast<ULONG_PTR*>(exceptionPtr) - 1;
|
|
auto partial = reinterpret_cast<RawExceptionData_Partial*>(*exceptionInfoPtr);
|
|
|
|
Platform::String^ message = exception->Message;
|
|
|
|
PCWSTR errorString = partial->restrictedErrorString;
|
|
PCWSTR messageString = reinterpret_cast<PCWSTR>(message ? message->Data() : nullptr);
|
|
|
|
// An old Platform::Exception^ bug that did not actually expose the error string out of the exception
|
|
// message. We do it by hand here if the message associated with the strong does not contain the
|
|
// message that was originally attached to the string (in the fixed version it will).
|
|
|
|
if ((errorString && *errorString && messageString) && (wcsstr(messageString, errorString) == nullptr))
|
|
{
|
|
return ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t*>(errorString));
|
|
}
|
|
return message;
|
|
}
|
|
|
|
inline void MaybeGetExceptionString(
|
|
_In_ Platform::Exception^ exception,
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
|
|
{
|
|
if (debugString)
|
|
{
|
|
auto message = GetPlatformExceptionMessage(exception);
|
|
auto messageString = !message ? L"(null Message)" : reinterpret_cast<PCWSTR>(message->Data());
|
|
StringCchPrintfW(debugString, debugStringChars, L"Platform::Exception^: %ws", messageString);
|
|
}
|
|
}
|
|
|
|
inline HRESULT ResultFromKnownException(
|
|
Platform::Exception^ exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
|
|
{
|
|
wchar_t message[2048];
|
|
message[0] = L'\0';
|
|
MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
|
|
auto hr = exception->HResult;
|
|
wil::details::ReportFailure_Base<FailureType::Log>(
|
|
__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message);
|
|
return hr;
|
|
}
|
|
|
|
inline HRESULT __stdcall ResultFromCaughtException_WinRt(
|
|
_Inout_updates_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Inout_ bool* isNormalized) WI_NOEXCEPT
|
|
{
|
|
if (g_pfnResultFromCaughtException)
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.GetErrorCode();
|
|
}
|
|
catch (Platform::Exception^ exception)
|
|
{
|
|
*isNormalized = true;
|
|
// We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error
|
|
// information out of the exception object and place it back into thread-local storage.
|
|
__abi_translateCurrentException(false);
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception->HResult;
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
catch (...)
|
|
{
|
|
auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.GetErrorCode();
|
|
}
|
|
catch (Platform::Exception^ exception)
|
|
{
|
|
*isNormalized = true;
|
|
// We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error
|
|
// information out of the exception object and place it back into thread-local storage.
|
|
__abi_translateCurrentException(false);
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception->HResult;
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
catch (std::exception& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
|
}
|
|
catch (...)
|
|
{
|
|
// Fall through to returning 'S_OK' below
|
|
}
|
|
}
|
|
|
|
// Tell the caller that we were unable to map the exception by succeeding...
|
|
return S_OK;
|
|
}
|
|
|
|
// WinRT supporting version to execute a functor and catch known exceptions.
|
|
inline HRESULT __stdcall ResultFromKnownExceptions_WinRt(
|
|
const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor)
|
|
{
|
|
WI_ASSERT(supported != SupportedExceptions::Default);
|
|
|
|
switch (supported)
|
|
{
|
|
case SupportedExceptions::Known:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (Platform::Exception^ exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (std::exception& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (...)
|
|
{
|
|
auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Unknown exception
|
|
throw;
|
|
}
|
|
break;
|
|
|
|
case SupportedExceptions::ThrownOrAlloc:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (Platform::Exception^ exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
break;
|
|
|
|
case SupportedExceptions::Thrown:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (Platform::Exception^ exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
break;
|
|
}
|
|
|
|
WI_ASSERT(false);
|
|
return S_OK;
|
|
}
|
|
|
|
inline void __stdcall ThrowPlatformException(FailureInfo const& failure, LPCWSTR debugString)
|
|
{
|
|
throw Platform::Exception::CreateException(
|
|
failure.hr, ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t*>(debugString)));
|
|
}
|
|
|
|
#if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS)
|
|
WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRt, [] {
|
|
g_pfnResultFromCaughtException_WinRt = ResultFromCaughtException_WinRt;
|
|
g_pfnResultFromKnownExceptions_WinRt = ResultFromKnownExceptions_WinRt;
|
|
g_pfnThrowPlatformException = ThrowPlatformException;
|
|
return 1;
|
|
});
|
|
#endif
|
|
#endif
|
|
// clang-format on
|
|
|
|
inline void __stdcall Rethrow()
|
|
{
|
|
throw;
|
|
}
|
|
|
|
inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure)
|
|
{
|
|
throw ResultException(failure);
|
|
}
|
|
|
|
__declspec(noinline) inline ResultStatus __stdcall ResultFromCaughtExceptionInternal(
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Out_ bool* isNormalized) WI_NOEXCEPT
|
|
{
|
|
if (debugString)
|
|
{
|
|
*debugString = L'\0';
|
|
}
|
|
*isNormalized = false;
|
|
|
|
if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr)
|
|
{
|
|
const auto hr = details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized);
|
|
if (FAILED(hr))
|
|
{
|
|
return ResultStatus::FromResult(hr);
|
|
}
|
|
}
|
|
|
|
if (details::g_pfnResultFromCaughtException_WinRt != nullptr)
|
|
{
|
|
const auto hr = details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized);
|
|
return ResultStatus::FromResult(hr);
|
|
}
|
|
|
|
if (g_pfnResultFromCaughtException)
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
*isNormalized = true;
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return ResultStatus::FromFailureInfo(exception.GetFailureInfo());
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return ResultStatus::FromResult(E_OUTOFMEMORY);
|
|
}
|
|
catch (...)
|
|
{
|
|
auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
|
|
if (FAILED(hr))
|
|
{
|
|
return ResultStatus::FromResult(hr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
*isNormalized = true;
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return ResultStatus::FromFailureInfo(exception.GetFailureInfo());
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return ResultStatus::FromResult(E_OUTOFMEMORY);
|
|
}
|
|
catch (std::exception& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
|
}
|
|
catch (...)
|
|
{
|
|
// Fall through to returning 'S_OK' below
|
|
}
|
|
}
|
|
|
|
// Tell the caller that we were unable to map the exception by succeeding...
|
|
return ResultStatus::FromResult(S_OK);
|
|
}
|
|
|
|
// Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and returning
|
|
// that HRESULT. Does NOT attempt to catch unknown exceptions (which propagate). Primarily used by SEH exception
|
|
// handling techniques to stop at the point the exception is thrown.
|
|
inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor)
|
|
{
|
|
if (supported == SupportedExceptions::Default)
|
|
{
|
|
supported = g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc;
|
|
}
|
|
|
|
if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) &&
|
|
((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) ||
|
|
(supported == SupportedExceptions::ThrownOrAlloc)))
|
|
{
|
|
return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor);
|
|
}
|
|
|
|
switch (supported)
|
|
{
|
|
case SupportedExceptions::Known:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (std::exception& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (...)
|
|
{
|
|
auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Unknown exception
|
|
throw;
|
|
}
|
|
|
|
case SupportedExceptions::ThrownOrAlloc:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
|
|
case SupportedExceptions::Thrown:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
return ResultFromKnownException(exception, diagnostics, returnAddress);
|
|
}
|
|
|
|
case SupportedExceptions::All:
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (...)
|
|
{
|
|
return wil::details::ReportFailure_CaughtException<FailureType::Log>(
|
|
__R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported);
|
|
}
|
|
|
|
case SupportedExceptions::None:
|
|
return functor.Run();
|
|
|
|
case SupportedExceptions::Default:
|
|
WI_ASSERT(false);
|
|
}
|
|
|
|
WI_ASSERT(false);
|
|
return S_OK;
|
|
}
|
|
|
|
inline HRESULT ResultFromExceptionSeh(
|
|
const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
|
|
{
|
|
__try
|
|
{
|
|
return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor);
|
|
}
|
|
__except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH)
|
|
{
|
|
WI_ASSERT(false);
|
|
RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
__declspec(noinline) inline HRESULT
|
|
ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
|
|
{
|
|
#ifdef RESULT_DEBUG
|
|
// We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions
|
|
// themselves or if the caller doesn't want to fail-fast unknown exceptions
|
|
if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions)
|
|
{
|
|
return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor);
|
|
}
|
|
#endif
|
|
try
|
|
{
|
|
return functor.Run();
|
|
}
|
|
catch (...)
|
|
{
|
|
return wil::details::ReportFailure_CaughtException<FailureType::Log>(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), supported);
|
|
}
|
|
}
|
|
|
|
__declspec(noinline) inline HRESULT
|
|
ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
|
|
{
|
|
return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor);
|
|
}
|
|
|
|
// Exception guard -- catch exceptions and log them (or handle them with a custom callback)
|
|
// WARNING: may throw an exception...
|
|
inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor& functor, IFunctorHost& host, void* returnAddress)
|
|
{
|
|
try
|
|
{
|
|
return host.Run(functor);
|
|
}
|
|
catch (...)
|
|
{
|
|
// Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the exception or
|
|
// return the remapped failure.
|
|
return host.ExceptionThrown(returnAddress);
|
|
}
|
|
}
|
|
|
|
WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultExceptions, [] {
|
|
g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter;
|
|
g_pfnRethrow = Rethrow;
|
|
g_pfnThrowResultException = ThrowResultExceptionInternal;
|
|
g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal;
|
|
return 1;
|
|
});
|
|
}
|
|
/// @endcond
|
|
|
|
//! A lambda-based exception guard that can vary the supported exception types.
|
|
//! This function accepts a lambda and diagnostics information as its parameters and executes that lambda
|
|
//! under a try/catch(...) block. All exceptions are caught and the function reports the exception information
|
|
//! and diagnostics to telemetry on failure. An HRESULT is returned that maps to the exception.
|
|
//!
|
|
//! Note that an overload exists that does not report failures to telemetry at all. This version should be preferred
|
|
//! to that version. Also note that neither of these versions are preferred over using try catch blocks to accomplish
|
|
//! the same thing as they will be more efficient.
|
|
//! ~~~~
|
|
//! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&]
|
|
//! {
|
|
//! // exception-based code
|
|
//! // telemetry is reported with full exception information
|
|
//! });
|
|
//! ~~~~
|
|
//! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter
|
|
//! @param supported What kind of exceptions you want to support
|
|
//! @param functor A lambda that accepts no parameters; any return value is ignored
|
|
//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown
|
|
template <typename Functor>
|
|
__forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT
|
|
{
|
|
static_assert(details::functor_tag<ErrorReturn::None, Functor>::value != details::tag_return_other::value, "Functor must return void or HRESULT");
|
|
typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(
|
|
wistd::forward<Functor>(functor));
|
|
|
|
return wil::details::ResultFromException(diagnostics, supported, functorObject);
|
|
}
|
|
|
|
//! A lambda-based exception guard.
|
|
//! This overload uses SupportedExceptions::Known by default. See @ref ResultFromException for more detailed information.
|
|
template <typename Functor>
|
|
__forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
|
|
{
|
|
return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward<Functor>(functor));
|
|
}
|
|
|
|
//! A lambda-based exception guard that does not report failures to telemetry.
|
|
//! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block.
|
|
//! All exceptions are caught and the function returns an HRESULT mapping to the exception.
|
|
//!
|
|
//! This version (taking only a lambda) does not report failures to telemetry. An overload with the same name
|
|
//! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter
|
|
//! to report failure information to telemetry.
|
|
//! ~~~~
|
|
//! hr = wil::ResultFromException([&]
|
|
//! {
|
|
//! // exception-based code
|
|
//! // the conversion of exception to HRESULT doesn't report telemetry
|
|
//! });
|
|
//!
|
|
//! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&]
|
|
//! {
|
|
//! // exception-based code
|
|
//! // telemetry is reported with full exception information
|
|
//! });
|
|
//! ~~~~
|
|
//! @param functor A lambda that accepts no parameters; any return value is ignored
|
|
//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown
|
|
template <typename Functor>
|
|
inline HRESULT ResultFromException(Functor&& functor) WI_NOEXCEPT
|
|
try
|
|
{
|
|
static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
|
|
typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(
|
|
wistd::forward<Functor>(functor));
|
|
|
|
functorObject.Run();
|
|
return S_OK;
|
|
}
|
|
catch (...)
|
|
{
|
|
return ResultFromCaughtException();
|
|
}
|
|
|
|
//! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported exception types.
|
|
//! Functionally this is nearly identical to the corresponding @ref ResultFromException function with the exception
|
|
//! that it utilizes structured exception handling internally to be able to terminate at the point where a unknown
|
|
//! exception is thrown, rather than after that unknown exception has been unwound. Though less efficient, this leads
|
|
//! to a better debugging experience when analyzing unknown exceptions.
|
|
//!
|
|
//! For example:
|
|
//! ~~~~
|
|
//! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&]
|
|
//! {
|
|
//! FunctionWhichMayThrow();
|
|
//! });
|
|
//! ~~~~
|
|
//! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`. This ends up
|
|
//! throwing a `long` as an exception object which is not what the caller intended. The normal @ref ResultFromException
|
|
//! would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() is already off of the
|
|
//! stack and has been unwound. Because SEH is used for ResultFromExceptionDebug, the fail-fast occurs with everything
|
|
//! leading up to and including the `throw INVALIDARG;` still on the stack (and easily debuggable).
|
|
//!
|
|
//! The penalty paid for using this, however, is efficiency. It's far less efficient as a general pattern than either
|
|
//! using ResultFromException directly or especially using try with CATCH_ macros directly. Still it's helpful to deploy
|
|
//! selectively to isolate issues a component may be having with unknown/unhandled exceptions.
|
|
//!
|
|
//! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected
|
|
//! exceptions not falling into the supported category easily through fail-fast. For example, by not supporting any
|
|
//! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the point
|
|
//! the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be tracked down.
|
|
//!
|
|
//! This will fail-fast and stop on std::exception based exceptions (but not Platform::Exception^ or wil::ResultException).
|
|
//! Using this can help isolate where an unexpected exception is being generated from.
|
|
//! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter
|
|
//! @param supported What kind of exceptions you want to support
|
|
//! @param functor A lambda that accepts no parameters; any return value is ignored
|
|
//! @return S_OK on success (no exception thrown) or an error based upon the exception thrown
|
|
template <typename Functor>
|
|
__forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT
|
|
{
|
|
static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
|
|
typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(
|
|
wistd::forward<Functor>(functor));
|
|
|
|
return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject);
|
|
}
|
|
|
|
//! A lambda-based exception guard that can identify the origin of unknown exceptions.
|
|
//! This overload uses SupportedExceptions::Known by default. See @ref ResultFromExceptionDebug for more detailed information.
|
|
template <typename Functor>
|
|
__forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
|
|
{
|
|
static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
|
|
typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(
|
|
wistd::forward<Functor>(functor));
|
|
|
|
return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject);
|
|
}
|
|
|
|
//! A fail-fast based exception guard.
|
|
//! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default. Any uncaught
|
|
//! exception that makes it back to this guard would result in a fail-fast at the point the exception is thrown.
|
|
template <typename Functor>
|
|
__forceinline void FailFastException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
|
|
{
|
|
static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
|
|
typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(
|
|
wistd::forward<Functor>(functor));
|
|
|
|
wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject);
|
|
}
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
|
|
#endif // WIL_ENABLE_EXCEPTIONS
|
|
|
|
// Exception guard -- catch exceptions and log them (or handle them with a custom callback)
|
|
// WARNING: may throw an exception...
|
|
inline __declspec(noinline) HRESULT RunFunctor(IFunctor& functor, IFunctorHost& host)
|
|
{
|
|
if (g_pfnRunFunctorWithExceptionFilter)
|
|
{
|
|
return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress());
|
|
}
|
|
|
|
return host.Run(functor);
|
|
}
|
|
|
|
// Returns true if a debugger should be considered to be connected.
|
|
// Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging),
|
|
// they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging),
|
|
// and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call
|
|
inline bool IsDebuggerPresent()
|
|
{
|
|
return g_fIsDebuggerPresent ||
|
|
((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Shared Reporting -- all reporting macros bubble up through this codepath
|
|
//*****************************************************************************
|
|
|
|
inline void LogFailure(
|
|
__R_FN_PARAMS_FULL,
|
|
FailureType type,
|
|
const ResultStatus& resultPair,
|
|
_In_opt_ PCWSTR message,
|
|
bool fWantDebugString,
|
|
_Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString,
|
|
_Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars,
|
|
_Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString,
|
|
_Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars,
|
|
_Out_ FailureInfo* failure) WI_NOEXCEPT
|
|
{
|
|
debugString[0] = L'\0';
|
|
callContextString[0] = L'\0';
|
|
|
|
static long volatile s_failureId = 0;
|
|
|
|
failure->hr = resultPair.hr;
|
|
failure->status = resultPair.status;
|
|
|
|
int failureCount = 0;
|
|
switch (type)
|
|
{
|
|
case FailureType::Exception:
|
|
failureCount = RecordException(failure->hr);
|
|
break;
|
|
case FailureType::Return:
|
|
failureCount = RecordReturn(failure->hr);
|
|
break;
|
|
case FailureType::Log:
|
|
if (SUCCEEDED(failure->hr))
|
|
{
|
|
// If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log
|
|
// success using one of the WIL macros. Example:
|
|
// LOG_HR(S_OK);
|
|
// Instead, use one of the forms that conditionally logs based upon the error condition:
|
|
// LOG_IF_FAILED(hr);
|
|
|
|
WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success.");
|
|
failure->hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE);
|
|
failure->status = wil::details::HrToNtStatus(failure->hr);
|
|
}
|
|
failureCount = RecordLog(failure->hr);
|
|
break;
|
|
case FailureType::FailFast:
|
|
failureCount = RecordFailFast(failure->hr);
|
|
break;
|
|
};
|
|
|
|
failure->type = type;
|
|
failure->flags = FailureFlags::None;
|
|
WI_SetFlagIf(failure->flags, FailureFlags::NtStatus, resultPair.kind == ResultStatus::Kind::NtStatus);
|
|
failure->failureId = ::InterlockedIncrementNoFence(&s_failureId);
|
|
failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr;
|
|
failure->threadId = ::GetCurrentThreadId();
|
|
failure->pszFile = fileName;
|
|
failure->uLineNumber = lineNumber;
|
|
failure->cFailureCount = failureCount;
|
|
failure->pszCode = code;
|
|
failure->pszFunction = functionName;
|
|
failure->returnAddress = returnAddress;
|
|
failure->callerReturnAddress = callerReturnAddress;
|
|
failure->pszCallContext = nullptr;
|
|
::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent));
|
|
::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating));
|
|
failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr;
|
|
|
|
// Process failure notification / adjustments
|
|
if (details::g_pfnNotifyFailure)
|
|
{
|
|
details::g_pfnNotifyFailure(failure);
|
|
}
|
|
|
|
// Completes filling out failure, notifies thread-based callbacks and the telemetry callback
|
|
if (details::g_pfnGetContextAndNotifyFailure)
|
|
{
|
|
details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars);
|
|
}
|
|
|
|
// Allow hooks to inspect the failure before acting upon it
|
|
if (details::g_pfnLoggingCallback)
|
|
{
|
|
details::g_pfnLoggingCallback(*failure);
|
|
}
|
|
|
|
// If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience
|
|
// for uncaught exceptions. In cases where we will be throwing a C++/CX Platform::Exception we should avoid originating because the
|
|
// CX runtime will be doing that for us. fWantDebugString is only set to true when the caller will be throwing a Platform::Exception.
|
|
if (details::g_pfnOriginateCallback && !fWantDebugString && WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry))
|
|
{
|
|
details::g_pfnOriginateCallback(*failure);
|
|
}
|
|
|
|
if (SUCCEEDED(failure->hr))
|
|
{
|
|
// Caller bug: Leaking a success code into a failure-only function
|
|
FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast);
|
|
failure->hr = E_UNEXPECTED;
|
|
failure->status = wil::details::HrToNtStatus(failure->hr);
|
|
}
|
|
|
|
bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString &&
|
|
WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry);
|
|
|
|
// We need to generate the logging message if:
|
|
// * We're logging to OutputDebugString
|
|
// * OR the caller asked us to (generally for attaching to a C++/CX exception)
|
|
if (fWantDebugString || fUseOutputDebugString)
|
|
{
|
|
// Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the
|
|
// console or the platform exception object if the caller desires it.
|
|
if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
|
|
{
|
|
g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars);
|
|
}
|
|
|
|
// The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still
|
|
// want it for OutputDebugString or exception message, then generate the default string.
|
|
if (debugString[0] == L'\0')
|
|
{
|
|
GetFailureLogString(debugString, debugStringSizeChars, *failure);
|
|
}
|
|
|
|
if (fUseOutputDebugString)
|
|
{
|
|
::OutputDebugStringW(debugString);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// [deprecated behavior]
|
|
// This callback was at one point *always* called for all failures, so we continue to call it for failures even when
|
|
// we don't need to generate the debug string information (when the callback was supplied directly). We can avoid
|
|
// this if the caller used the explicit function (through g_resultMessageCallbackSet)
|
|
if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
|
|
{
|
|
g_pfnResultLoggingCallback(failure, nullptr, 0);
|
|
}
|
|
}
|
|
|
|
if ((WI_IsFlagSet(failure->flags, FailureFlags::RequestDebugBreak) || g_fBreakOnFailure) && (g_pfnDebugBreak != nullptr))
|
|
{
|
|
g_pfnDebugBreak();
|
|
}
|
|
}
|
|
|
|
inline RESULT_NORETURN void __stdcall WilFailFast(const wil::FailureInfo& failure)
|
|
{
|
|
if (g_pfnWilFailFast)
|
|
{
|
|
g_pfnWilFailFast(failure);
|
|
}
|
|
|
|
#ifdef RESULT_RAISE_FAST_FAIL_EXCEPTION
|
|
// Use of this macro is an ODR violation - use the callback instead. This will be removed soon.
|
|
RESULT_RAISE_FAST_FAIL_EXCEPTION;
|
|
#endif
|
|
|
|
// Before we fail fast in this method, give the [optional] RoFailFastWithErrorContext a try.
|
|
if (g_pfnFailfastWithContextCallback)
|
|
{
|
|
g_pfnFailfastWithContextCallback(failure);
|
|
}
|
|
|
|
// parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT)
|
|
EXCEPTION_RECORD er{};
|
|
er.NumberParameters = 1; // default to be safe, see below
|
|
er.ExceptionCode = static_cast<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
|
|
if (failure.returnAddress == nullptr) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it
|
|
{
|
|
// passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing
|
|
// !analyze functionality to crawl the stack looking for the HRESULT
|
|
// don't pass a 0 HRESULT in param 1 because that will result in worse bucketing.
|
|
WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
|
|
}
|
|
else // use FailureInfo caller address
|
|
{
|
|
// parameter 1 is the failing HRESULT
|
|
// parameter 2 is the line number. This is never used for bucketing (due to code churn causing re-bucketing) but is available in the dump's
|
|
// exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps.
|
|
er.NumberParameters = 3;
|
|
er.ExceptionInformation[1] = failure.hr;
|
|
er.ExceptionInformation[2] = failure.uLineNumber;
|
|
er.ExceptionAddress = failure.returnAddress;
|
|
WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */);
|
|
}
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline __declspec(noinline) void ReportFailure_Return(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
bool needPlatformException =
|
|
((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) &&
|
|
(g_pfnThrowPlatformException != nullptr) &&
|
|
(g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException)));
|
|
|
|
FailureInfo failure;
|
|
wchar_t debugString[2048];
|
|
char callContextString[1024];
|
|
|
|
LogFailure(
|
|
__R_FN_CALL_FULL,
|
|
T,
|
|
resultPair,
|
|
message,
|
|
needPlatformException,
|
|
debugString,
|
|
ARRAYSIZE(debugString),
|
|
callContextString,
|
|
ARRAYSIZE(callContextString),
|
|
&failure);
|
|
|
|
if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast))
|
|
{
|
|
WilFailFast(failure);
|
|
}
|
|
}
|
|
|
|
template <FailureType T, bool SuppressAction>
|
|
inline __declspec(noinline) void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
ReportFailure_Return<T>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline __declspec(noinline) RESULT_NORETURN
|
|
void ReportFailure_NoReturn(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
bool needPlatformException =
|
|
((T == FailureType::Exception) && WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) &&
|
|
(g_pfnThrowPlatformException != nullptr) &&
|
|
(g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException)));
|
|
|
|
FailureInfo failure;
|
|
wchar_t debugString[2048];
|
|
char callContextString[1024];
|
|
|
|
LogFailure(
|
|
__R_FN_CALL_FULL,
|
|
T,
|
|
resultPair,
|
|
message,
|
|
needPlatformException,
|
|
debugString,
|
|
ARRAYSIZE(debugString),
|
|
callContextString,
|
|
ARRAYSIZE(callContextString),
|
|
&failure);
|
|
__WI_SUPPRESS_4127_S
|
|
if ((T == FailureType::FailFast) || WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast))
|
|
{
|
|
WilFailFast(const_cast<FailureInfo&>(failure));
|
|
}
|
|
else
|
|
{
|
|
if (needPlatformException)
|
|
{
|
|
g_pfnThrowPlatformException(failure, debugString);
|
|
}
|
|
|
|
if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow))
|
|
{
|
|
RethrowCaughtException();
|
|
}
|
|
|
|
ThrowResultException(failure);
|
|
|
|
// Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup)
|
|
WilFailFast(const_cast<FailureInfo&>(failure));
|
|
}
|
|
__WI_SUPPRESS_4127_E
|
|
}
|
|
|
|
template <>
|
|
inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base<FailureType::FailFast, false>(
|
|
__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
ReportFailure_NoReturn<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
}
|
|
|
|
template <>
|
|
inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base<FailureType::Exception, false>(
|
|
__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
ReportFailure_NoReturn<FailureType::Exception>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
}
|
|
|
|
__declspec(noinline) inline void ReportFailure(
|
|
__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message, ReportFailureOptions options)
|
|
{
|
|
switch (type)
|
|
{
|
|
case FailureType::Exception:
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
break;
|
|
case FailureType::FailFast:
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
break;
|
|
case FailureType::Log:
|
|
ReportFailure_Base<FailureType::Log>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
break;
|
|
case FailureType::Return:
|
|
ReportFailure_Base<FailureType::Return>(__R_FN_CALL_FULL, resultPair, message, options);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline ResultStatus ReportFailure_CaughtExceptionCommon(
|
|
__R_FN_PARAMS_FULL,
|
|
_Inout_updates_(debugStringChars) PWSTR debugString,
|
|
_Pre_satisfies_(debugStringChars > 0) size_t debugStringChars,
|
|
SupportedExceptions supported)
|
|
{
|
|
bool isNormalized = false;
|
|
auto length = wcslen(debugString);
|
|
WI_ASSERT(length < debugStringChars);
|
|
ResultStatus resultPair;
|
|
if (details::g_pfnResultFromCaughtExceptionInternal)
|
|
{
|
|
resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized);
|
|
}
|
|
|
|
const bool known = (FAILED(resultPair.hr));
|
|
if (!known)
|
|
{
|
|
resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
|
}
|
|
|
|
ReportFailureOptions options = ReportFailureOptions::ForcePlatformException;
|
|
WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized);
|
|
|
|
if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) ||
|
|
((supported == SupportedExceptions::Thrown) && !isNormalized) ||
|
|
((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions))
|
|
{
|
|
// By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or
|
|
// wil::ResultException based types and Platform::Exception^, so there aren't too many valid exception types which
|
|
// could cause this. Those that are valid, should be handled by remapping the exception callback. Those that are not
|
|
// valid should be found and fixed (meaningless accidents like 'throw hr;'). The caller may also be requesting
|
|
// non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions).
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, debugString, options);
|
|
}
|
|
else
|
|
{
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, resultPair, debugString, options);
|
|
}
|
|
|
|
return resultPair;
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline ResultStatus RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase(
|
|
__R_FN_PARAMS_FULL,
|
|
_Inout_updates_(debugStringChars) PWSTR debugString,
|
|
_Pre_satisfies_(debugStringChars > 0) size_t debugStringChars,
|
|
SupportedExceptions supported)
|
|
{
|
|
bool isNormalized = false;
|
|
const auto length = wcslen(debugString);
|
|
WI_ASSERT(length < debugStringChars);
|
|
ResultStatus resultPair;
|
|
if (details::g_pfnResultFromCaughtExceptionInternal)
|
|
{
|
|
resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized);
|
|
}
|
|
|
|
const bool known = (FAILED(resultPair.hr));
|
|
if (!known)
|
|
{
|
|
resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION));
|
|
}
|
|
|
|
ReportFailureOptions options = ReportFailureOptions::ForcePlatformException;
|
|
WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized);
|
|
|
|
if ((supported == SupportedExceptions::None) || ((supported == SupportedExceptions::Known) && !known) ||
|
|
((supported == SupportedExceptions::Thrown) && !isNormalized) ||
|
|
((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions))
|
|
{
|
|
// By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or
|
|
// wil::ResultException based types and Platform::Exception^, so there aren't too many valid exception types which
|
|
// could cause this. Those that are valid, should be handled by remapping the exception callback. Those that are not
|
|
// valid should be found and fixed (meaningless accidents like 'throw hr;'). The caller may also be requesting
|
|
// non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions).
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, debugString, options);
|
|
}
|
|
else
|
|
{
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, resultPair, debugString, options);
|
|
}
|
|
|
|
RESULT_NORETURN_RESULT(resultPair);
|
|
}
|
|
|
|
template <>
|
|
inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL,
|
|
_Inout_updates_(debugStringChars) PWSTR debugString,
|
|
_Pre_satisfies_(debugStringChars > 0) size_t debugStringChars,
|
|
SupportedExceptions supported)
|
|
{
|
|
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase<FailureType::FailFast>(
|
|
__R_FN_CALL_FULL, debugString, debugStringChars, supported));
|
|
}
|
|
|
|
template <>
|
|
inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL,
|
|
_Inout_updates_(debugStringChars) PWSTR debugString,
|
|
_Pre_satisfies_(debugStringChars > 0) size_t debugStringChars,
|
|
SupportedExceptions supported)
|
|
{
|
|
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase<FailureType::Exception>(
|
|
__R_FN_CALL_FULL, debugString, debugStringChars, supported));
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, resultPair, message);
|
|
}
|
|
|
|
template <>
|
|
inline RESULT_NORETURN void ReportFailure_Msg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, message);
|
|
}
|
|
|
|
template <>
|
|
inline RESULT_NORETURN void ReportFailure_Msg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, resultPair, message);
|
|
}
|
|
|
|
template <FailureType T>
|
|
inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr)
|
|
{
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr<FailureType::FailFast>(__R_FN_PARAMS_FULL, HRESULT hr)
|
|
{
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr<FailureType::Exception>(__R_FN_PARAMS_FULL, HRESULT hr)
|
|
{
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
}
|
|
|
|
__declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr)
|
|
{
|
|
switch (type)
|
|
{
|
|
case FailureType::Exception:
|
|
ReportFailure_Hr<FailureType::Exception>(__R_FN_CALL_FULL, hr);
|
|
break;
|
|
case FailureType::FailFast:
|
|
ReportFailure_Hr<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
|
|
break;
|
|
case FailureType::Log:
|
|
ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL, hr);
|
|
break;
|
|
case FailureType::Return:
|
|
ReportFailure_Hr<FailureType::Return>(__R_FN_CALL_FULL, hr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err)
|
|
{
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32<FailureType::FailFast>(__R_FN_PARAMS_FULL, DWORD err)
|
|
{
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32<FailureType::Exception>(__R_FN_PARAMS_FULL, DWORD err)
|
|
{
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
::SetLastError(err);
|
|
return err;
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError<FailureType::FailFast>(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(err);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError<FailureType::Exception>(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
const auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(err);
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr<FailureType::FailFast>(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr<FailureType::Exception>(__R_FN_PARAMS_FULL)
|
|
{
|
|
const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr));
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Base<T>(__R_FN_CALL_FULL, resultPair);
|
|
return resultPair.hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus<FailureType::FailFast>(__R_FN_PARAMS_FULL, NTSTATUS status)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Base<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair);
|
|
RESULT_NORETURN_RESULT(resultPair.hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus<FailureType::Exception>(__R_FN_PARAMS_FULL, NTSTATUS status)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Base<FailureType::Exception>(__R_FN_CALL_FULL, resultPair);
|
|
RESULT_NORETURN_RESULT(resultPair.hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
|
{
|
|
wchar_t message[2048]{};
|
|
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr;
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT
|
|
ReportFailure_CaughtException<FailureType::FailFast>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
|
{
|
|
wchar_t message[2048]{};
|
|
RESULT_NORETURN_RESULT(
|
|
ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT
|
|
ReportFailure_CaughtException<FailureType::Exception>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
|
|
{
|
|
wchar_t message[2048]{};
|
|
RESULT_NORETURN_RESULT(
|
|
ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN
|
|
void ReportFailure_HrMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN
|
|
void ReportFailure_HrMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline HRESULT
|
|
ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline DWORD
|
|
ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
::SetLastError(err);
|
|
return err;
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(err);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto err = GetLastErrorFail(__R_FN_CALL_FULL);
|
|
auto hr = __HRESULT_FROM_WIN32(err);
|
|
ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(err);
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline HRESULT
|
|
ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
return hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
|
|
ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList);
|
|
RESULT_NORETURN_RESULT(hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline HRESULT
|
|
ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Msg<T>(__R_FN_CALL_FULL, resultPair, formatString, argList);
|
|
return resultPair.hr;
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, resultPair, formatString, argList);
|
|
RESULT_NORETURN_RESULT(resultPair.hr);
|
|
}
|
|
|
|
template <>
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
const auto resultPair = ResultStatus::FromStatus(status);
|
|
ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, resultPair, formatString, argList);
|
|
RESULT_NORETURN_RESULT(resultPair.hr);
|
|
}
|
|
|
|
template <FailureType T>
|
|
__declspec(noinline) inline HRESULT
|
|
ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
// Pre-populate the buffer with our message, the exception message will be added to it...
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
|
return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).hr;
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg<FailureType::FailFast>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
// Pre-populate the buffer with our message, the exception message will be added to it...
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
|
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(
|
|
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
|
.hr);
|
|
}
|
|
|
|
template <>
|
|
__declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg<FailureType::Exception>(
|
|
__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
// Pre-populate the buffer with our message, the exception message will be added to it...
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
StringCchCatW(message, ARRAYSIZE(message), L" -- ");
|
|
RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon<FailureType::Exception>(
|
|
__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)
|
|
.hr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Support for throwing custom exception types
|
|
//*****************************************************************************
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
inline HRESULT GetErrorCode(_In_ ResultException& exception) WI_NOEXCEPT
|
|
{
|
|
return exception.GetErrorCode();
|
|
}
|
|
|
|
inline void SetFailureInfo(_In_ FailureInfo const& failure, _Inout_ ResultException& exception) WI_NOEXCEPT
|
|
{
|
|
return exception.SetFailureInfo(failure);
|
|
}
|
|
|
|
// clang-format off
|
|
#ifdef __cplusplus_winrt
|
|
inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT
|
|
{
|
|
return exception->HResult;
|
|
}
|
|
|
|
inline void SetFailureInfo(_In_ FailureInfo const&, _Inout_ Platform::Exception^ exception) WI_NOEXCEPT
|
|
{
|
|
// no-op -- once a PlatformException^ is created, we can't modify the message, but this function must
|
|
// exist to distinguish this from ResultException
|
|
}
|
|
#endif
|
|
// clang-format on
|
|
|
|
template <typename T>
|
|
RESULT_NORETURN inline void ReportFailure_CustomExceptionHelper(_Inout_ T& exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr)
|
|
{
|
|
// When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'"
|
|
// Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h.
|
|
// This compilation error indicates an attempt to throw an incompatible exception type.
|
|
const HRESULT hr = GetErrorCode(exception);
|
|
|
|
FailureInfo failure;
|
|
wchar_t debugString[2048];
|
|
char callContextString[1024];
|
|
|
|
LogFailure(
|
|
__R_FN_CALL_FULL,
|
|
FailureType::Exception,
|
|
ResultStatus::FromResult(hr),
|
|
message,
|
|
false, // false = does not need debug string
|
|
debugString,
|
|
ARRAYSIZE(debugString),
|
|
callContextString,
|
|
ARRAYSIZE(callContextString),
|
|
&failure);
|
|
|
|
if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast))
|
|
{
|
|
WilFailFast(failure);
|
|
}
|
|
|
|
// push the failure info context into the custom exception class
|
|
SetFailureInfo(failure, exception);
|
|
|
|
throw exception;
|
|
}
|
|
|
|
template <typename T>
|
|
__declspec(noinline) RESULT_NORETURN inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception)
|
|
{
|
|
__R_FN_LOCALS_RA;
|
|
ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL);
|
|
}
|
|
|
|
template <typename T>
|
|
__declspec(noinline) RESULT_NORETURN
|
|
inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
wchar_t message[2048];
|
|
PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
|
|
|
|
__R_FN_LOCALS_RA;
|
|
ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message);
|
|
}
|
|
#endif
|
|
|
|
namespace __R_NS_NAME
|
|
{
|
|
//*****************************************************************************
|
|
// Return Macros
|
|
//*****************************************************************************
|
|
|
|
__R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Return>(__R_DIRECT_FN_CALL hr);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_Win32<FailureType::Return>(__R_DIRECT_FN_CALL err);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_GetLastErrorHr<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_NtStatus<FailureType::Return>(__R_DIRECT_FN_CALL status);
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
#endif
|
|
|
|
__R_DIRECT_METHOD(void, Return_HrMsg)
|
|
(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Return>(__R_DIRECT_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_Win32_to_HRESULT_(err)
|
|
__R_DIRECT_METHOD(HRESULT, Return_Win32Msg)
|
|
(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_Win32Msg<FailureType::Return>(__R_DIRECT_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_last_error_to_HRESULT_
|
|
__R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)
|
|
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_GetLastErrorHrMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
|
|
_Success_(true)
|
|
_Translates_NTSTATUS_to_HRESULT_(status)
|
|
__R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)
|
|
(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_NtStatusMsg<FailureType::Return>(__R_DIRECT_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__R_DIRECT_METHOD(HRESULT, Return_CaughtExceptionMsg)
|
|
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
// Log Macros
|
|
//*****************************************************************************
|
|
|
|
_Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Log>(__R_DIRECT_FN_CALL hr);
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == err) __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::Log>(__R_DIRECT_FN_CALL err);
|
|
return err;
|
|
}
|
|
|
|
__R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_GetLastError<FailureType::Log>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
|
|
_Post_satisfies_(return == status) __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::Log>(__R_DIRECT_FN_CALL status);
|
|
return status;
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_CaughtException<FailureType::Log>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
#endif
|
|
|
|
__R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Log>(__R_INTERNAL_FN_CALL hr);
|
|
}
|
|
|
|
__R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastError<FailureType::Log>(__R_INTERNAL_FN_CALL_ONLY);
|
|
}
|
|
|
|
__R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::Log>(__R_INTERNAL_FN_CALL err);
|
|
}
|
|
|
|
__R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Log>(__R_INTERNAL_FN_CALL E_OUTOFMEMORY);
|
|
}
|
|
|
|
__R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::Log>(__R_INTERNAL_FN_CALL status);
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == hr) __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)(
|
|
__R_CONDITIONAL_FN_PARAMS HRESULT hr, unsigned int expectedCount, ...) WI_NOEXCEPT
|
|
{
|
|
va_list args;
|
|
va_start(args, expectedCount);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
unsigned int expectedIndex;
|
|
for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex)
|
|
{
|
|
if (hr == va_arg(args, HRESULT))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (expectedIndex == expectedCount)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
}
|
|
|
|
va_end(args);
|
|
return hr;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == ret) __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret)
|
|
{
|
|
if (!ret)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == err) __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err)
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == handle) __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == handle) __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)
|
|
(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == condition)
|
|
__R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == condition)
|
|
__R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == status)
|
|
__R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status)
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
_Post_satisfies_(return == hr)
|
|
__R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_DIRECT_FN_CALL hr, formatString, argList);
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == err)
|
|
__R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::Log>(__R_DIRECT_FN_CALL err, formatString, argList);
|
|
return err;
|
|
}
|
|
|
|
__R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)
|
|
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_GetLastErrorMsg<FailureType::Log>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
|
|
_Post_satisfies_(return == status) __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(
|
|
__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::Log>(__R_DIRECT_FN_CALL status, formatString, argList);
|
|
return status;
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__R_DIRECT_METHOD(HRESULT, Log_CaughtExceptionMsg)
|
|
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
return wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Log>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
#endif
|
|
|
|
__R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastErrorMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == ret) __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!ret)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
_Post_satisfies_(return == err) __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)(
|
|
__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
return status;
|
|
}
|
|
} // namespace __R_NS_NAME
|
|
|
|
namespace __RFF_NS_NAME
|
|
{
|
|
//*****************************************************************************
|
|
// FailFast Macros
|
|
//*****************************************************************************
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_DIRECT_FN_CALL hr);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::FailFast>(__RFF_DIRECT_FN_CALL err);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastError<FailureType::FailFast>(__RFF_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::FailFast>(__RFF_DIRECT_FN_CALL status);
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_CaughtException<FailureType::FailFast>(__RFF_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
#endif
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL hr);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastError<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL_ONLY);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL err);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL status);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT
|
|
{
|
|
if (!ret)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
_Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err)
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNullAlloc)
|
|
(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)
|
|
(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)
|
|
(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)
|
|
(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastErrorMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)
|
|
(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg)
|
|
(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_CaughtExceptionMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
#endif
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastErrorMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
|
|
}
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!ret)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
_Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_HrIfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_DIRECT_FN_CALL E_UNEXPECTED);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL E_UNEXPECTED);
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)(
|
|
__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)
|
|
(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL E_UNEXPECTED, formatString, argList);
|
|
}
|
|
|
|
__RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)
|
|
(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
|
|
{
|
|
__RFF_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, formatString, argList);
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)
|
|
(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)
|
|
(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// FailFast Immediate Macros
|
|
//*****************************************************************************
|
|
|
|
__RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT
|
|
{
|
|
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
|
}
|
|
|
|
__RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT
|
|
{
|
|
__fastfail(FAST_FAIL_FATAL_APP_EXIT);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT
|
|
{
|
|
if (condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT
|
|
{
|
|
if (!condition)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull)
|
|
(_Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
// Should be decorated WI_NOEXCEPT, but conflicts with forceinline.
|
|
template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)
|
|
(_In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
|
|
__RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
__RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
|
|
}
|
|
return status;
|
|
}
|
|
} // namespace __RFF_NS_NAME
|
|
|
|
namespace __R_NS_NAME
|
|
{
|
|
//*****************************************************************************
|
|
// Exception Macros
|
|
//*****************************************************************************
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
__R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Exception>(__R_DIRECT_FN_CALL hr);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::Exception>(__R_DIRECT_FN_CALL err);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastError<FailureType::Exception>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::Exception>(__R_DIRECT_FN_CALL status);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_CaughtException<FailureType::Exception>(__R_DIRECT_FN_CALL_ONLY);
|
|
}
|
|
|
|
__R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Exception>(__R_INTERNAL_FN_CALL hr);
|
|
}
|
|
|
|
__R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastError<FailureType::Exception>(__R_INTERNAL_FN_CALL_ONLY);
|
|
}
|
|
|
|
__R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32<FailureType::Exception>(__R_INTERNAL_FN_CALL err);
|
|
}
|
|
|
|
__R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Hr<FailureType::Exception>(__R_INTERNAL_FN_CALL E_OUTOFMEMORY);
|
|
}
|
|
|
|
__R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatus<FailureType::Exception>(__R_INTERNAL_FN_CALL status);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret)
|
|
{
|
|
if (!ret)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
_Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err)
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)
|
|
(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)
|
|
(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(bool, Throw_Win32If)(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition)
|
|
{
|
|
if (condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)
|
|
(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status)
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
__R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_HrMsg)
|
|
(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_DIRECT_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_Win32Msg)
|
|
(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::Exception>(__R_DIRECT_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastErrorMsg<FailureType::Exception>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg)
|
|
(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::Exception>(__R_DIRECT_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
__R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg)
|
|
(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Exception>(__R_DIRECT_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_GetLastErrorMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_Win32Msg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
|
|
}
|
|
|
|
__R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg)
|
|
(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
|
|
{
|
|
__R_FN_LOCALS;
|
|
wil::details::ReportFailure_NtStatusMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
|
|
_Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (FAILED(hr))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
_Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (!ret)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
_Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (FAILED_WIN32(err))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
_Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (handle == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_Win32IfMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
_Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (!condition)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
|
|
_Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
|
|
__WI_SUPPRESS_NULLPTR_ANALYSIS _When_(pointer == nullptr, _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (pointer == nullptr)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
|
|
}
|
|
}
|
|
|
|
_Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
|
|
__R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg)
|
|
(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...)
|
|
{
|
|
if (FAILED_NTSTATUS(status))
|
|
{
|
|
va_list argList;
|
|
va_start(argList, formatString);
|
|
__R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)
|
|
(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
|
|
}
|
|
return status;
|
|
}
|
|
#endif // WIL_ENABLE_EXCEPTIONS
|
|
|
|
} // namespace __R_NS_NAME
|
|
} // namespace details
|
|
/// @endcond
|
|
|
|
//*****************************************************************************
|
|
// Error Handling Policies to switch between error-handling style
|
|
//*****************************************************************************
|
|
// The following policies are used as template policies for components that can support exception, fail-fast, and
|
|
// error-code based modes.
|
|
|
|
// Use for classes which should return HRESULTs as their error-handling policy
|
|
// Intentionally removed logging from this policy as logging is more useful at the caller.
|
|
struct err_returncode_policy
|
|
{
|
|
using result = HRESULT;
|
|
|
|
__forceinline static HRESULT Win32BOOL(BOOL fReturn)
|
|
{
|
|
RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn);
|
|
return S_OK;
|
|
}
|
|
__forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
|
{
|
|
*ph = h;
|
|
RETURN_LAST_ERROR_IF_NULL_EXPECTED(h);
|
|
return S_OK;
|
|
}
|
|
_Post_satisfies_(return == hr) __forceinline static HRESULT HResult(HRESULT hr)
|
|
{
|
|
return hr;
|
|
}
|
|
__forceinline static HRESULT LastError()
|
|
{
|
|
return wil::details::GetLastErrorFailHr();
|
|
}
|
|
__forceinline static HRESULT LastErrorIfFalse(bool condition)
|
|
{
|
|
RETURN_LAST_ERROR_IF_EXPECTED(!condition);
|
|
return S_OK;
|
|
}
|
|
_Post_satisfies_(return == S_OK) __forceinline static HRESULT OK()
|
|
{
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
// Use for classes which fail-fast on errors
|
|
struct err_failfast_policy
|
|
{
|
|
typedef _Return_type_success_(true) void result;
|
|
__forceinline static result Win32BOOL(BOOL fReturn)
|
|
{
|
|
FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn);
|
|
}
|
|
__forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
|
{
|
|
*ph = h;
|
|
FAIL_FAST_LAST_ERROR_IF_NULL(h);
|
|
}
|
|
_When_(FAILED(hr), _Analysis_noreturn_)
|
|
__forceinline static result HResult(HRESULT hr)
|
|
{
|
|
FAIL_FAST_IF_FAILED(hr);
|
|
}
|
|
__forceinline static result LastError()
|
|
{
|
|
FAIL_FAST_LAST_ERROR();
|
|
}
|
|
__forceinline static result LastErrorIfFalse(bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
FAIL_FAST_LAST_ERROR();
|
|
}
|
|
}
|
|
__forceinline static result OK()
|
|
{
|
|
}
|
|
};
|
|
|
|
#ifdef WIL_ENABLE_EXCEPTIONS
|
|
// Use for classes which should return through exceptions as their error-handling policy
|
|
struct err_exception_policy
|
|
{
|
|
typedef _Return_type_success_(true) void result;
|
|
__forceinline static result Win32BOOL(BOOL fReturn)
|
|
{
|
|
THROW_IF_WIN32_BOOL_FALSE(fReturn);
|
|
}
|
|
__forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE* ph)
|
|
{
|
|
*ph = h;
|
|
THROW_LAST_ERROR_IF_NULL(h);
|
|
}
|
|
_When_(FAILED(hr), _Analysis_noreturn_)
|
|
__forceinline static result HResult(HRESULT hr)
|
|
{
|
|
THROW_IF_FAILED(hr);
|
|
}
|
|
__forceinline static result LastError()
|
|
{
|
|
THROW_LAST_ERROR();
|
|
}
|
|
__forceinline static result LastErrorIfFalse(bool condition)
|
|
{
|
|
if (!condition)
|
|
{
|
|
THROW_LAST_ERROR();
|
|
}
|
|
}
|
|
__forceinline static result OK()
|
|
{
|
|
}
|
|
};
|
|
#else
|
|
// NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined
|
|
// (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at
|
|
// template instantiation time since this type lacks required member functions. An alternative would be to have some
|
|
// 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available,
|
|
// but that may have unexpected side effects when compiling code that expects to be using exceptions
|
|
struct err_exception_policy
|
|
{
|
|
};
|
|
#endif
|
|
|
|
} // namespace wil
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif // defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
|
|
#endif // __WIL_RESULTMACROS_INCLUDED
|