//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the MIT License.
//    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
//    ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//    TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
//    PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
#ifndef __WIL_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
#ifndef RESULT_DEBUG
#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !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(condition)                                (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L"" #condition), DbgRaiseAssertionFailure(), 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(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 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
#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


//*****************************************************************************
// 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
//*****************************************************************************

#ifndef RESULT_NORETURN
#define RESULT_NORETURN                                     __declspec(noreturn)
#endif
#ifndef RESULT_NORETURN_NULL
#define RESULT_NORETURN_NULL                                _Ret_notnull_
#endif

//*****************************************************************************
// 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

// 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, 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, 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, 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, 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) 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, 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, 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)

#define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e))
#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), fmt, ##__VA_ARGS__)
#define LOG_LAST_ERROR_MSG(fmt, ...)                            __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
#define LOG_WIN32_MSG(win32err, fmt, ...)                       __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define LOG_NTSTATUS_MSG(status, fmt, ...)                      __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, 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), fmt, ##__VA_ARGS__)
#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)        __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...)              __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...)                    __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, 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), fmt, ##__VA_ARGS__)
#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...)                   __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__)
#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...)              __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)               __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)            __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__)

#define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e)
#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), fmt, ##__VA_ARGS__)
#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...)                      __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) fmt, ##__VA_ARGS__)
#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...)                 __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...)                __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, 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), fmt, ##__VA_ARGS__)
#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)  __RFF_FN(FailFast_IfWin32BoolFalseMsg)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...)        __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...)              __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, 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), 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, fmt, ##__VA_ARGS__)
#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...)        __RFF_FN(FailFast_GetLastErrorIfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)         __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)      __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, 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) 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), fmt, ##__VA_ARGS__)
#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...)                    __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, 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)


//*****************************************************************************
// 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_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), fmt, ##__VA_ARGS__)
#define THROW_LAST_ERROR_MSG(fmt, ...)                          __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
#define THROW_WIN32_MSG(win32err, fmt, ...)                     __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define THROW_EXCEPTION_MSG(exception, fmt, ...)                wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, fmt, ##__VA_ARGS__)
#define THROW_NTSTATUS_MSG(status, fmt, ...)                    __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, 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), fmt, ##__VA_ARGS__)
#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)      __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...)            __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...)                  __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, 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), fmt, ##__VA_ARGS__)
#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...)                 __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__)
#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...)            __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)             __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)          __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, 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) 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) 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) 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) 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(__R_FN_CALL_FULL, FailureType::Log, 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(__R_FN_CALL_FULL, FailureType::Log, 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
//*****************************************************************************
#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

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_...
    };

    /** 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;
        HRESULT hr;
        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;

        _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));
        }
    }
    /// @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:
                pszType = "ReturnHr";
                break;
            case FailureType::Log:
                pszType = "LogHr";
                break;
            case FailureType::FailFast:
                pszType = "FailFast";
                break;
            }

            wchar_t szErrorText[256];
            szErrorText[0] = L'\0';
            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(), failure.hr, 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;
        };

        // 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_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) HRESULT(__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;

        enum class ReportFailureOptions
        {
            None                    = 0x00,
            ForcePlatformException  = 0x01,
            SuppressAction          = 0x02,
            MayRethrow              = 0x04,
        };
        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
        {
            typedef tag_return_other type;
        };

        template <>
        struct return_type<ErrorReturn::Auto, HRESULT>
        {
            typedef tag_return_HRESULT type;
        };

        template <>
        struct return_type<ErrorReturn::Auto, void>
        {
            typedef tag_return_void type;
        };

        template <>
        struct return_type<ErrorReturn::None, void>
        {
            typedef tag_return_void type;
        };

        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 __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;
        }

        __declspec(noreturn) inline void __stdcall WilFailFast(const FailureInfo& info);
        inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _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;
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_) __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None);
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_) inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...);
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_) __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr);
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_) __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, FailureType type, 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
            {
                assign(other.m_pCopy, other.m_size);
                return *this;
            }

            shared_buffer& operator=(shared_buffer &&other) WI_NOEXCEPT
            {
                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);
            }

            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);
            }

            size_t size() const WI_NOEXCEPT
            {
                return m_size;
            }

            explicit operator bool() const WI_NOEXCEPT
            {
                return (m_pCopy != nullptr);
            }

            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
            {
                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
            {
                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;
            }

            object_t* get() const WI_NOEXCEPT
            {
                return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object;
            }

            explicit operator bool() const WI_NOEXCEPT
            {
                return (m_pCopy != nullptr);
            }

            bool unique() const WI_NOEXCEPT
            {
                return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1));
            }

            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)

        __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;
        }

        inline __declspec(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);
        }

        // 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).  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;
        }

        _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;
            if ((psz == NULL) || (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;
            size_t cchMax;
            size_t cchNewDestLength = 0;

            // leave the last space for the null terminator
            cchMax = cchDest - 1;
#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, NULL, 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));
            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 = min(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0])));
            __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd));
            return pReturn;
        }
    } // details namespace
    /// @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
    }
    /// @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:
        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();
        }

        //! 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();
            }
        }

        //! 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;
    }

    // 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);
        }

        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)) HRESULT GetErrorCode() const WI_NOEXCEPT
        {
            HRESULT const hr = m_failure.GetFailureInfo().hr;
            __analysis_assume(hr < 0);
            return hr;
        }

        //! Get a reference to the stored FailureInfo.
        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.
        inline const char * __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override
        {
            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());
        }

        // 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);
        }
        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
        //*****************************************************************************

        __declspec(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];
            message[0] = L'\0';
            MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
            auto hr = exception.GetErrorCode();
            wil::details::ReportFailure(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, hr, message);
            return hr;
        }

        inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
        {
            wchar_t message[2048];
            message[0] = L'\0';
            MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
            constexpr auto hr = E_OUTOFMEMORY;
            wil::details::ReportFailure(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, hr, message);
            return hr;
        }

        inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
        {
            wchar_t message[2048];
            message[0] = L'\0';
            MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
            constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
            wil::details::ReportFailure(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, hr, message);
            return hr;
        }

        inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress)
        {
            if (g_pfnResultFromCaughtException_CppWinRt)
            {
                wchar_t message[2048];
                message[0] = L'\0';
                bool ignored;
                auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored);
                if (FAILED(hr))
                {
                    ReportFailure(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, 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 (...)
                {
                }
            }

            return hr;
        }

#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(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, 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;
                    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;
                    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

        inline void __stdcall Rethrow()
        {
            throw;
        }

        inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure)
        {
            throw ResultException(failure);
        }

        __declspec(noinline) inline HRESULT __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)
            {
                RETURN_IF_FAILED_EXPECTED(details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized));
            }

            if (details::g_pfnResultFromCaughtException_WinRt != nullptr)
            {
                return details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized);
            }

            if (g_pfnResultFromCaughtException)
            {
                try
                {
                    throw;
                }
                catch (const ResultException& exception)
                {
                    *isNormalized = true;
                    MaybeGetExceptionString(exception, debugString, debugStringChars);
                    return exception.GetErrorCode();
                }
                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)
                {
                    *isNormalized = true;
                    MaybeGetExceptionString(exception, debugString, debugStringChars);
                    return exception.GetErrorCode();
                }
                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;
        }

        // 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(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), FailureType::Log, supported);
                }

            case SupportedExceptions::None:
                return functor.Run();
            }

            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);
            }
        }

        __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
        {
#ifdef RESULT_DEBUG
            // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions
            // themselves or if the caller doesn't want to fail-fast unknown exceptions
            if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions)
            {
                return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor);
            }
#endif
            try
            {
                return functor.Run();
            }
            catch (...)
            {
                return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), FailureType::Log, 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;
        });

    }

    //! 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.
    //!
    //! See @ref page_exception_guards for more information and examples on exception guards.
    //! ~~~~
    //! 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.
    //!
    //! See @ref page_exception_guards for more information and examples on exception guards.
    //! ~~~~
    //! 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.
    //!
    //! Also see @ref ResultFromExceptionDebugNoStdException.  It functions almost identically, but also 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);
    }

    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, HRESULT hr, _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;

            int failureCount = 0;
            switch (type)
            {
            case FailureType::Exception:
                failureCount = RecordException(hr);
                break;
            case FailureType::Return:
                failureCount = RecordReturn(hr);
                break;
            case FailureType::Log:
                if (SUCCEEDED(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.");
                    hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE);
                }
                failureCount = RecordLog(hr);
                break;
            case FailureType::FailFast:
                failureCount = RecordFailFast(hr);
                break;
            };

            failure->type = type;
            failure->hr = hr;
            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;

            // 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.
            if (details::g_pfnOriginateCallback)
            {
                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;
            }

            bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString;

            // 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 (g_fBreakOnFailure && (g_pfnDebugBreak != nullptr))
            {
                g_pfnDebugBreak();
            }
        }

        inline __declspec(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

            // 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 == 0)                     // 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 */);
            }
        }

        _Use_decl_annotations_
        inline __declspec(noinline) void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, PCWSTR message, ReportFailureOptions options)
        {
            bool needPlatformException = ((type == 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, type, hr, message, needPlatformException,
                debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure);

            if (WI_IsFlagClear(options, ReportFailureOptions::SuppressAction))
            {
                if (type == FailureType::FailFast)
                {
                    WilFailFast(const_cast<FailureInfo&>(failure));
                }
                else if (type == FailureType::Exception)
                {
                    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));
                }
            }
        }

        inline HRESULT ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, FailureType type, _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);
            HRESULT hr = S_OK;
            if (details::g_pfnResultFromCaughtExceptionInternal)
            {
                hr = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized);
            }

            const bool known = (FAILED(hr));
            if (!known)
            {
                hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
            }

            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).

                type = FailureType::FailFast;
            }

            ReportFailureOptions options = ReportFailureOptions::ForcePlatformException;
            WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized);
            ReportFailure(__R_FN_CALL_FULL, type, hr, debugString, options);
            return hr;
        }

        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            wchar_t message[2048];
            PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
            ReportFailure(__R_FN_CALL_FULL, type, hr, message);
        }

        _Use_decl_annotations_
        inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, PCSTR formatString, ...)
        {
            va_list argList;
            va_start(argList, formatString);
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
        }

        _Use_decl_annotations_
        __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr)
        {
            ReportFailure(__R_FN_CALL_FULL, type, hr);
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_Win32_to_HRESULT_(err)
        __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, FailureType type, DWORD err)
        {
            const auto hr = __HRESULT_FROM_WIN32(err);
            ReportFailure(__R_FN_CALL_FULL, type, hr);
            return hr;
        }

        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL, FailureType type)
        {
            const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
            const auto hr = __HRESULT_FROM_WIN32(err);
            ReportFailure(__R_FN_CALL_FULL, type, hr);
            return err;
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_last_error_to_HRESULT_
        __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL, FailureType type)
        {
            const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
            ReportFailure(__R_FN_CALL_FULL, type, hr);
            return hr;
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_NTSTATUS_to_HRESULT_(status)
        __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, FailureType type, NTSTATUS status)
        {
            const auto hr = wil::details::NtStatusToHr(status);
            ReportFailure(__R_FN_CALL_FULL, type, hr);
            return hr;
        }

        _Use_decl_annotations_
        __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, FailureType type, SupportedExceptions supported)
        {
            wchar_t message[2048];
            message[0] = L'\0';
            return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, type, message, ARRAYSIZE(message), supported);
        }

        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_Win32_to_HRESULT_(err)
        __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, FailureType type, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            auto hr = __HRESULT_FROM_WIN32(err);
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
            return hr;
        }

        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, FailureType type, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            auto err = GetLastErrorFail(__R_FN_CALL_FULL);
            auto hr = __HRESULT_FROM_WIN32(err);
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
            return err;
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_last_error_to_HRESULT_
        __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, FailureType type, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
            return hr;
        }

        _Success_(true)
        _When_((type == FailureType::Exception) || (type == FailureType::FailFast), _Analysis_noreturn_)
        _Translates_NTSTATUS_to_HRESULT_(status)
        __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, FailureType type, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            auto hr = wil::details::NtStatusToHr(status);
            ReportFailure_Msg(__R_FN_CALL_FULL, type, hr, formatString, argList);
            return hr;
        }

        __declspec(noinline) inline HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, FailureType type, _Printf_format_string_ PCSTR formatString, va_list argList)
        {
            // Pre-populate the buffer with our message, the exception message will be added to it...
            wchar_t message[2048];
            PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
            StringCchCatW(message, ARRAYSIZE(message), L" -- ");
            return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, type, message, ARRAYSIZE(message), SupportedExceptions::Default);
        }


        //*****************************************************************************
        // 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);
        }

#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

        template <typename T>
        __declspec(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, hr, message, false,     // false = does not need debug string
                       debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure);

            // push the failure info context into the custom exception class
            SetFailureInfo(failure, exception);

            throw exception;
        }

        template <typename T>
        __declspec(noreturn, noinline) 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(noreturn, noinline) inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...)
        {
            va_list argList;
            va_start(argList, formatString);
            wchar_t message[2048];
            PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);

            __R_FN_LOCALS_RA;
            ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message);
        }
#endif

        namespace __R_NS_NAME
        {
            //*****************************************************************************
            // Return Macros
            //*****************************************************************************

            __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::Return, 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(__R_DIRECT_FN_CALL FailureType::Return, err);
            }

            _Success_(true)
            _Translates_last_error_to_HRESULT_
            __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL FailureType::Return);
            }

            _Success_(true)
            _Translates_NTSTATUS_to_HRESULT_(status)
            __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Return, status);
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL FailureType::Return);
            }
#endif

            __R_DIRECT_METHOD(void, Return_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL FailureType::Return, hr, formatString, argList);
            }

            _Success_(true)
            _Translates_Win32_to_HRESULT_(err)
            __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL FailureType::Return, err, formatString, argList);
            }

            _Success_(true)
            _Translates_last_error_to_HRESULT_
            __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_GetLastErrorHrMsg(__R_DIRECT_FN_CALL FailureType::Return, formatString, argList);
            }

            _Success_(true)
            _Translates_NTSTATUS_to_HRESULT_(status)
            __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL FailureType::Return, status, formatString, argList);
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __R_DIRECT_METHOD(HRESULT, Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL FailureType::Return, formatString, argList);
            }
#endif

            //*****************************************************************************
            // Log Macros
            //*****************************************************************************

            _Use_decl_annotations_
            __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL FailureType::Log, hr);
                return hr;
            }

            _Post_satisfies_(return == err)
            __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::Log, err);
                return err;
            }

            __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL FailureType::Log);
            }

            _Post_satisfies_(return == status)
            __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Log, status);
                return status;
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL FailureType::Log);
            }
#endif

            __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Log, hr);
            }

            __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL FailureType::Log);
            }

            __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL FailureType::Log, err);
            }

            __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Log, E_OUTOFMEMORY);
            }

            __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL FailureType::Log, status);
            }

            _Post_satisfies_(return == hr)
            __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
            {
                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;
            }

            _Post_satisfies_(return == ret)
            __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT
            {
                if (!ret)
                {
                    __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
                }
                return ret;
            }

            _Post_satisfies_(return == err)
            __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                if (FAILED_WIN32(err))
                {
                    __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err);
                }
                return err;
            }

            _Post_satisfies_(return == handle)
            __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
            {
                if (handle == INVALID_HANDLE_VALUE)
                {
                    __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
                }
                return handle;
            }

            _Post_satisfies_(return == handle)
            __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
            {
                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);
                }
            }

            _Post_satisfies_(return == condition)
            __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
            {
                if (condition)
                {
                    __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
                }
                return condition;
            }

            _Post_satisfies_(return == condition)
            __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
            {
                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);
                }
            }

            _Post_satisfies_(return == condition)
            __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
            {
                if (condition)
                {
                    __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
                }
                return condition;
            }

            _Post_satisfies_(return == condition)
            __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
            {
                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);
                }
            }

            _Post_satisfies_(return == status)
            __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                if (FAILED_NTSTATUS(status))
                {
                    __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status);
                }
                return status;
            }

            _Use_decl_annotations_
            __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL FailureType::Log, hr, formatString, argList);
                return hr;
            }

            _Use_decl_annotations_
            __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL FailureType::Log, err, formatString, argList);
                return err;
            }

            __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL FailureType::Log, formatString, argList);
            }

            _Post_satisfies_(return == status)
            __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL FailureType::Log, status, formatString, argList);
                return status;
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __R_DIRECT_METHOD(HRESULT, Log_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __R_FN_LOCALS;
                return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL FailureType::Log, formatString, argList);
            }
#endif

            __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, hr, formatString, argList);
            }

            __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, formatString, argList);
            }

            __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, err, formatString, argList);
            }

            __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, E_OUTOFMEMORY, formatString, argList);
            }

            __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Log, 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(__RFF_DIRECT_FN_CALL FailureType::FailFast, hr);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL FailureType::FailFast, err);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL FailureType::FailFast);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL FailureType::FailFast, status);
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_CaughtException(__RFF_DIRECT_FN_CALL FailureType::FailFast);
            }
#endif

            __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, hr);
            }

            __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL FailureType::FailFast);
            }

            __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL FailureType::FailFast, err);
            }

            __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, E_OUTOFMEMORY);
            }

            __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL FailureType::FailFast, 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;
            }

            _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
            __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT
            {
                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;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
                return pointer;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
            }

            _Use_decl_annotations_
            __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;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
                }
                return pointer;
            }

            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) WI_NOEXCEPT
            {
                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;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
                return pointer;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
            }

            _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
            __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
            {
                if (FAILED_NTSTATUS(status))
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status);
                }
                return status;
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, hr, formatString, argList);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL FailureType::FailFast, err, formatString, argList);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, formatString, argList);
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, status, formatString, argList);
            }

#ifdef WIL_ENABLE_EXCEPTIONS
            __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_CaughtExceptionMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, formatString, argList);
            }
#endif

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, hr, formatString, argList);
            }

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_GetLastErrorMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, formatString, argList);
            }

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, err, formatString, argList);
            }

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, E_OUTOFMEMORY, formatString, argList);
            }

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, 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(__RFF_DIRECT_FN_CALL FailureType::FailFast, E_UNEXPECTED);
            }

            __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL FailureType::FailFast, E_UNEXPECTED);
            }

            _Use_decl_annotations_
            __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;
            }

            _Use_decl_annotations_
            __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;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
                return pointer;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
                }
            }

            __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
            {
                va_list argList;
                va_start(argList, formatString);
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL FailureType::FailFast, E_UNEXPECTED, formatString, argList);
            }

            __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
            {
                __RFF_FN_LOCALS;
                wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL FailureType::FailFast, 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;
            }

            _Use_decl_annotations_
            __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;
            }

            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) WI_NOEXCEPT
            {
                if (pointer == nullptr)
                {
                    __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
                }
                return pointer;
            }

            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) WI_NOEXCEPT
            {
                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(__R_DIRECT_FN_CALL FailureType::Exception, hr);
            }

            __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL FailureType::Exception, err);
            }

            __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL FailureType::Exception);
            }

            __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL FailureType::Exception, status);
            }

            __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL FailureType::Exception);
            }

            __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Exception, hr);
            }

            __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL FailureType::Exception);
            }

            __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL FailureType::Exception, err);
            }

            __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL FailureType::Exception, E_OUTOFMEMORY);
            }

            __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status)
            {
                __R_FN_LOCALS;
                wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL FailureType::Exception, 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_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(__R_DIRECT_FN_CALL FailureType::Exception, 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(__R_DIRECT_FN_CALL FailureType::Exception, 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(__R_DIRECT_FN_CALL FailureType::Exception, 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(__R_DIRECT_FN_CALL FailureType::Exception, 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(__R_DIRECT_FN_CALL FailureType::Exception, 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(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, 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(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, 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(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, 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(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, 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(__R_INTERNAL_NOINLINE_FN_CALL FailureType::Exception, 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_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

        }   // __R_NS_NAME namespace
    }   // details namespace
    /// @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
    {
        typedef HRESULT result;

        __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
