1 //*********************************************************
2 //
3 //    Copyright (c) Microsoft. All rights reserved.
4 //    This code is licensed under the MIT License.
5 //    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
6 //    ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
7 //    TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
8 //    PARTICULAR PURPOSE AND NONINFRINGEMENT.
9 //
10 //*********************************************************
11 #ifndef __WIL_RESULTMACROS_INCLUDED
12 #define __WIL_RESULTMACROS_INCLUDED
13 
14 // WARNING:
15 // Code within this scope must satisfy both C99 and C++
16 
17 #include "common.h"
18 
19 #if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
20 #include <Windows.h>
21 #endif
22 
23 // Setup the debug behavior
24 #ifndef RESULT_DEBUG
25 #if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG)
26 #define RESULT_DEBUG
27 #endif
28 #endif
29 
30 /// @cond
31 #if defined(_PREFAST_)
32 #define __WI_ANALYSIS_ASSUME(_exp)                          _Analysis_assume_(_exp)
33 #else
34 #ifdef RESULT_DEBUG
35 #define __WI_ANALYSIS_ASSUME(_exp)                          ((void) 0)
36 #else
37 // NOTE: Clang does not currently handle __noop correctly and will fail to compile if the argument is not copy
38 //       constructible. Therefore, use 'sizeof' for syntax validation. We don't do this universally for all compilers
39 //       since lambdas are not allowed in unevaluated contexts prior to C++20, which does not appear to affect __noop
40 #if !defined(_MSC_VER) || defined(__clang__)
41 #define __WI_ANALYSIS_ASSUME(_exp)                          ((void)sizeof(_exp)) // Validate syntax on non-debug builds
42 #else
43 #define __WI_ANALYSIS_ASSUME(_exp)                          __noop(_exp)
44 #endif
45 #endif
46 #endif // _PREFAST_
47 
48 //*****************************************************************************
49 // Assert Macros
50 //*****************************************************************************
51 
52 #ifdef RESULT_DEBUG
53 #if defined(__clang__) && defined(_WIN32)
54 // Clang currently mis-handles '__annotation' for 32-bit - https://bugs.llvm.org/show_bug.cgi?id=41890
55 #define __WI_ASSERT_FAIL_ANNOTATION(msg) (void)0
56 #else
57 #define __WI_ASSERT_FAIL_ANNOTATION(msg) __annotation(L"Debug", L"AssertFail", msg)
58 #endif
59 
60 #define WI_ASSERT(condition)                                (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L"" #condition), DbgRaiseAssertionFailure(), FALSE) : TRUE))
61 #define WI_ASSERT_MSG(condition, msg)                       (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE))
62 #define WI_ASSERT_NOASSUME                                  WI_ASSERT
63 #define WI_ASSERT_MSG_NOASSUME                              WI_ASSERT_MSG
64 #define WI_VERIFY                                           WI_ASSERT
65 #define WI_VERIFY_MSG                                       WI_ASSERT_MSG
66 #define WI_VERIFY_SUCCEEDED(condition)                      WI_ASSERT(SUCCEEDED(condition))
67 #else
68 #define WI_ASSERT(condition)                                (__WI_ANALYSIS_ASSUME(condition), 0)
69 #define WI_ASSERT_MSG(condition, msg)                       (__WI_ANALYSIS_ASSUME(condition), 0)
70 #define WI_ASSERT_NOASSUME(condition)                       ((void) 0)
71 #define WI_ASSERT_MSG_NOASSUME(condition, msg)              ((void) 0)
72 #define WI_VERIFY(condition)                                (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE))
73 #define WI_VERIFY_MSG(condition, msg)                       (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE))
74 #define WI_VERIFY_SUCCEEDED(condition)                      (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE))
75 #endif // RESULT_DEBUG
76 
77 #if !defined(_NTDEF_)
78 typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
79 #endif
80 #ifndef STATUS_SUCCESS
81 #define STATUS_SUCCESS              ((NTSTATUS)0x00000000L)
82 #endif
83 #ifndef STATUS_UNSUCCESSFUL
84 #define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)
85 #endif
86 
87 #ifndef WIL_AllocateMemory
88 #ifdef _KERNEL_MODE
89 #define WIL_AllocateMemory(SIZE)    ExAllocatePoolWithTag(NonPagedPoolNx, SIZE, 'LIW')
90 WI_ODR_PRAGMA("WIL_AllocateMemory", "2")
91 #else
92 #define WIL_AllocateMemory(SIZE)    HeapAlloc(GetProcessHeap(), 0, SIZE)
93 WI_ODR_PRAGMA("WIL_AllocateMemory", "1")
94 #endif
95 #else
96 WI_ODR_PRAGMA("WIL_AllocateMemory", "0")
97 #endif
98 
99 #ifndef WIL_FreeMemory
100 #ifdef _KERNEL_MODE
101 #define WIL_FreeMemory(MEM)         ExFreePoolWithTag(MEM, 'LIW')
102 WI_ODR_PRAGMA("WIL_FreeMemory", "2")
103 #else
104 #define WIL_FreeMemory(MEM)         HeapFree(GetProcessHeap(), 0, MEM)
105 WI_ODR_PRAGMA("WIL_FreeMemory", "1")
106 #endif
107 #else
108 WI_ODR_PRAGMA("WIL_FreeMemory", "0")
109 #endif
110 
111 // It would appear as though the C++17 "noexcept is part of the type system" update in MSVC has "infected" the behavior
112 // when compiling with C++14 (the default...), however the updated behavior for decltype understanding noexcept is _not_
113 // present... So, work around it
114 #if __WI_LIBCPP_STD_VER >= 17
115 #define WI_PFN_NOEXCEPT WI_NOEXCEPT
116 #else
117 #define WI_PFN_NOEXCEPT
118 #endif
119 /// @endcond
120 
121 #if defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
122 
123 #include <strsafe.h>
124 #include <intrin.h>     // provides the _ReturnAddress() intrinsic
125 #include <new.h>        // provides 'operator new', 'std::nothrow', etc.
126 #if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW)
127 #include <new>          // provides std::bad_alloc in the windows and public CRT headers
128 #endif
129 
130 #pragma warning(push)
131 #pragma warning(disable:4714 6262)    // __forceinline not honored, stack size
132 
133 //*****************************************************************************
134 // Behavioral setup (error handling macro configuration)
135 //*****************************************************************************
136 // Set any of the following macros to the values given below before including Result.h to
137 // control the error handling macro's trade-offs between diagnostics and performance
138 
139 // RESULT_DIAGNOSTICS_LEVEL
140 // This define controls the level of diagnostic instrumentation that is built into the binary as a
141 // byproduct of using the macros.  The amount of diagnostic instrumentation that is supplied is
142 // a trade-off between diagnosibility of issues and code size and performance.  The modes are:
143 //      0   - No diagnostics, smallest & fastest (subject to tail-merge)
144 //      1   - No diagnostics, unique call sites for each macro (defeat's tail-merge)
145 //      2   - Line number
146 //      3   - Line number + source filename
147 //      4   - Line number + source filename + function name
148 //      5   - Line number + source filename + function name + code within the macro
149 // By default, mode 3 is used in free builds and mode 5 is used in checked builds.  Note that the
150 // _ReturnAddress() will always be available through all modes when possible.
151 
152 // RESULT_INCLUDE_CALLER_RETURNADDRESS
153 // This controls whether or not the _ReturnAddress() of the function that includes the macro will
154 // be reported to telemetry.  Note that this is in addition to the _ReturnAddress() of the actual
155 // macro position (which is always reported).  The values are:
156 //      0   - The address is not included
157 //      1   - The address is included
158 // The default value is '1'.
159 
160 // RESULT_INLINE_ERROR_TESTS
161 // For conditional macros (other than RETURN_XXX), this controls whether branches will be evaluated
162 // within the call containing the macro or will be forced into the function called by the macros.
163 // Pushing branching into the called function reduces code size and the number of unique branches
164 // evaluated, but increases the instruction count executed per macro.
165 //      0   - Branching will not happen inline to the macros
166 //      1   - Branching is pushed into the calling function via __forceinline
167 // The default value is '1'.  Note that XXX_MSG functions are always effectively mode '0' due to the
168 // compiler's unwillingness to inline var-arg functions.
169 
170 // RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST
171 // RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST
172 // RESULT_INLINE_ERROR_TESTS_FAIL_FAST
173 // These defines are identical to those above in form/function, but only applicable to fail fast error
174 // handling allowing a process to have different diagnostic information and performance characteristics
175 // for fail fast than for other error handling given the different reporting infrastructure (Watson
176 // vs Telemetry).
177 
178 // Set the default diagnostic mode
179 // Note that RESULT_DEBUG_INFO and RESULT_SUPPRESS_DEBUG_INFO are older deprecated models of controlling mode
180 #ifndef RESULT_DIAGNOSTICS_LEVEL
181 #if (defined(RESULT_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO)
182 #define RESULT_DIAGNOSTICS_LEVEL 5
183 #else
184 #define RESULT_DIAGNOSTICS_LEVEL 3
185 #endif
186 #endif
187 #ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS
188 #define RESULT_INCLUDE_CALLER_RETURNADDRESS 1
189 #endif
190 #ifndef RESULT_INLINE_ERROR_TESTS
191 #define RESULT_INLINE_ERROR_TESTS 1
192 #endif
193 #ifndef RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST
194 #define RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST RESULT_DIAGNOSTICS_LEVEL
195 #endif
196 #ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST
197 #define RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST RESULT_INCLUDE_CALLER_RETURNADDRESS
198 #endif
199 #ifndef RESULT_INLINE_ERROR_TESTS_FAIL_FAST
200 #define RESULT_INLINE_ERROR_TESTS_FAIL_FAST RESULT_INLINE_ERROR_TESTS
201 #endif
202 
203 
204 //*****************************************************************************
205 // Win32 specific error macros
206 //*****************************************************************************
207 
208 #define FAILED_WIN32(win32err)                              ((win32err) != 0)
209 #define SUCCEEDED_WIN32(win32err)                           ((win32err) == 0)
210 
211 
212 //*****************************************************************************
213 // NT_STATUS specific error macros
214 //*****************************************************************************
215 
216 #define FAILED_NTSTATUS(status)                             (((NTSTATUS)(status)) < 0)
217 #define SUCCEEDED_NTSTATUS(status)                          (((NTSTATUS)(status)) >= 0)
218 
219 
220 //*****************************************************************************
221 // Testing helpers - redefine to run unit tests against fail fast
222 //*****************************************************************************
223 
224 #ifndef RESULT_NORETURN
225 #define RESULT_NORETURN                                     __declspec(noreturn)
226 #endif
227 #ifndef RESULT_NORETURN_NULL
228 #define RESULT_NORETURN_NULL                                _Ret_notnull_
229 #endif
230 
231 //*****************************************************************************
232 // Helpers to setup the macros and functions used below... do not directly use.
233 //*****************************************************************************
234 
235 /// @cond
236 #define __R_DIAGNOSTICS(diagnostics)                        diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr
237 #define __R_DIAGNOSTICS_RA(diagnostics, address)            diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr, address
238 #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
239 #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();
240 // NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases
241 //       This entire section will be repeated below for fail fast (__RFF_ prefix).
242 #define __R_COMMA ,
243 #define __R_FN_CALL_FULL                                    callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress
244 #define __R_FN_CALL_FULL_RA                                 callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress()
245 // The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly
246 #if (RESULT_DIAGNOSTICS_LEVEL >= 2)  // line number
247 #define __R_IF_LINE(term) term
248 #define __R_IF_NOT_LINE(term)
249 #define __R_IF_COMMA ,
250 #define __R_LINE_VALUE static_cast<unsigned short>(__LINE__)
251 #else
252 #define __R_IF_LINE(term)
253 #define __R_IF_NOT_LINE(term) term
254 #define __R_IF_COMMA
255 #define __R_LINE_VALUE static_cast<unsigned short>(0)
256 #endif
257 #if (RESULT_DIAGNOSTICS_LEVEL >= 3) // line number + file name
258 #define __R_IF_FILE(term) term
259 #define __R_IF_NOT_FILE(term)
260 #define __R_FILE_VALUE __FILE__
261 #else
262 #define __R_IF_FILE(term)
263 #define __R_IF_NOT_FILE(term) term
264 #define __R_FILE_VALUE nullptr
265 #endif
266 #if (RESULT_DIAGNOSTICS_LEVEL >= 4) // line number + file name + function name
267 #define __R_IF_FUNCTION(term) term
268 #define __R_IF_NOT_FUNCTION(term)
269 #else
270 #define __R_IF_FUNCTION(term)
271 #define __R_IF_NOT_FUNCTION(term) term
272 #endif
273 #if (RESULT_DIAGNOSTICS_LEVEL >= 5) // line number + file name + function name + macro code
274 #define __R_IF_CODE(term) term
275 #define __R_IF_NOT_CODE(term)
276 #else
277 #define __R_IF_CODE(term)
278 #define __R_IF_NOT_CODE(term) term
279 #endif
280 #if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1)
281 #define __R_IF_CALLERADDRESS(term) term
282 #define __R_IF_NOT_CALLERADDRESS(term)
283 #define __R_CALLERADDRESS_VALUE _ReturnAddress()
284 #else
285 #define __R_IF_CALLERADDRESS(term)
286 #define __R_IF_NOT_CALLERADDRESS(term) term
287 #define __R_CALLERADDRESS_VALUE nullptr
288 #endif
289 #if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) || (RESULT_DIAGNOSTICS_LEVEL >= 2)
290 #define __R_IF_TRAIL_COMMA ,
291 #else
292 #define __R_IF_TRAIL_COMMA
293 #endif
294 // Assemble the varying amounts of data into a single macro
295 #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)
296 #define __R_INFO(CODE)                                      __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA
297 #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)
298 #define __R_INFO_NOFILE(CODE)                               __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA
299 #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)
300 #define __R_FN_PARAMS                                       __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA
301 #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)
302 #define __R_FN_CALL                                         __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA
303 #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;)
304 #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();
305 #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;)
306 // 1) Direct Methods
307 //      * Called Directly by Macros
308 //      * Always noinline
309 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1)
310 #if (RESULT_DIAGNOSTICS_LEVEL == 1)
311 #define __R_DIRECT_METHOD(RetType, MethodName)              template <unsigned int optimizerCounter> inline __declspec(noinline) RetType MethodName
312 #define __R_DIRECT_NORET_METHOD(RetType, MethodName)        template <unsigned int optimizerCounter> inline __declspec(noinline) RESULT_NORETURN RetType MethodName
313 #else
314 #define __R_DIRECT_METHOD(RetType, MethodName)              inline __declspec(noinline) RetType MethodName
315 #define __R_DIRECT_NORET_METHOD(RetType, MethodName)        inline __declspec(noinline) RESULT_NORETURN RetType MethodName
316 #endif
317 #define __R_DIRECT_FN_PARAMS                                __R_FN_PARAMS
318 #define __R_DIRECT_FN_PARAMS_ONLY                           __R_FN_PARAMS_ONLY
319 #define __R_DIRECT_FN_CALL                                  __R_FN_CALL_FULL_RA __R_COMMA
320 #define __R_DIRECT_FN_CALL_ONLY                             __R_FN_CALL_FULL_RA
321 // 2) Internal Methods
322 //      * Only called by Conditional routines
323 //      * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined)
324 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1)
325 #if (RESULT_DIAGNOSTICS_LEVEL == 1)
326 #define __R_INTERNAL_NOINLINE_METHOD(MethodName)            inline __declspec(noinline) void MethodName
327 #define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName)      inline __declspec(noinline) RESULT_NORETURN void MethodName
328 #define __R_INTERNAL_INLINE_METHOD(MethodName)              template <unsigned int optimizerCounter> inline __declspec(noinline) void MethodName
329 #define __R_INTERNAL_INLINE_NORET_METHOD(MethodName)        template <unsigned int optimizerCounter> inline __declspec(noinline) RESULT_NORETURN void MethodName
330 #define __R_CALL_INTERNAL_INLINE_METHOD(MethodName)         MethodName <optimizerCounter>
331 #else
332 #define __R_INTERNAL_NOINLINE_METHOD(MethodName)            inline void MethodName
333 #define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName)      inline RESULT_NORETURN void MethodName
334 #define __R_INTERNAL_INLINE_METHOD(MethodName)              inline __declspec(noinline) void MethodName
335 #define __R_INTERNAL_INLINE_NORET_METHOD(MethodName)        inline __declspec(noinline) RESULT_NORETURN void MethodName
336 #define __R_CALL_INTERNAL_INLINE_METHOD(MethodName)         MethodName
337 #endif
338 #define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName)       MethodName
339 #define __R_INTERNAL_NOINLINE_FN_PARAMS                     __R_FN_PARAMS void* returnAddress __R_COMMA
340 #define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY                __R_FN_PARAMS void* returnAddress
341 #define __R_INTERNAL_NOINLINE_FN_CALL                       __R_FN_CALL_FULL __R_COMMA
342 #define __R_INTERNAL_NOINLINE_FN_CALL_ONLY                  __R_FN_CALL_FULL
343 #define __R_INTERNAL_INLINE_FN_PARAMS                       __R_FN_PARAMS
344 #define __R_INTERNAL_INLINE_FN_PARAMS_ONLY                  __R_FN_PARAMS_ONLY
345 #define __R_INTERNAL_INLINE_FN_CALL                         __R_FN_CALL_FULL_RA __R_COMMA
346 #define __R_INTERNAL_INLINE_FN_CALL_ONLY                    __R_FN_CALL_FULL_RA
347 #if (RESULT_INLINE_ERROR_TESTS == 0)
348 #define __R_INTERNAL_METHOD                                 __R_INTERNAL_NOINLINE_METHOD
349 #define __R_INTERNAL_NORET_METHOD                           __R_INTERNAL_NOINLINE_NORET_METHOD
350 #define __R_CALL_INTERNAL_METHOD                            __R_CALL_INTERNAL_NOINLINE_METHOD
351 #define __R_INTERNAL_FN_PARAMS                              __R_INTERNAL_NOINLINE_FN_PARAMS
352 #define __R_INTERNAL_FN_PARAMS_ONLY                         __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY
353 #define __R_INTERNAL_FN_CALL                                __R_INTERNAL_NOINLINE_FN_CALL
354 #define __R_INTERNAL_FN_CALL_ONLY                           __R_INTERNAL_NOINLINE_FN_CALL_ONLY
355 #else
356 #define __R_INTERNAL_METHOD                                 __R_INTERNAL_INLINE_METHOD
357 #define __R_INTERNAL_NORET_METHOD                           __R_INTERNAL_INLINE_NORET_METHOD
358 #define __R_CALL_INTERNAL_METHOD                            __R_CALL_INTERNAL_INLINE_METHOD
359 #define __R_INTERNAL_FN_PARAMS                              __R_INTERNAL_INLINE_FN_PARAMS
360 #define __R_INTERNAL_FN_PARAMS_ONLY                         __R_INTERNAL_INLINE_FN_PARAMS_ONLY
361 #define __R_INTERNAL_FN_CALL                                __R_INTERNAL_INLINE_FN_CALL
362 #define __R_INTERNAL_FN_CALL_ONLY                           __R_INTERNAL_INLINE_FN_CALL_ONLY
363 #endif
364 // 3) Conditional Methods
365 //      * Called Directly by Macros
366 //      * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS)
367 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1)
368 #if (RESULT_DIAGNOSTICS_LEVEL == 1)
369 #define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName)            template <unsigned int optimizerCounter> inline __declspec(noinline) RetType MethodName
370 #define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName)   inline __declspec(noinline) RetType MethodName
371 #define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName)              template <unsigned int optimizerCounter> __forceinline RetType MethodName
372 #define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName)     __forceinline RetType MethodName
373 #define __R_CONDITIONAL_PARTIAL_TEMPLATE                                unsigned int optimizerCounter __R_COMMA
374 #else
375 #define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName)            inline __declspec(noinline) RetType MethodName
376 #define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName)   inline __declspec(noinline) RetType MethodName
377 #define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName)              __forceinline RetType MethodName
378 #define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName)     __forceinline RetType MethodName
379 #define __R_CONDITIONAL_PARTIAL_TEMPLATE
380 #endif
381 #define __R_CONDITIONAL_NOINLINE_FN_CALL                    __R_FN_CALL _ReturnAddress() __R_COMMA
382 #define __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY               __R_FN_CALL _ReturnAddress()
383 #define __R_CONDITIONAL_INLINE_FN_CALL                      __R_FN_CALL
384 #define __R_CONDITIONAL_INLINE_FN_CALL_ONLY                 __R_FN_CALL_ONLY
385 #if (RESULT_INLINE_ERROR_TESTS == 0)
386 #define __R_CONDITIONAL_METHOD                              __R_CONDITIONAL_NOINLINE_METHOD
387 #define __R_CONDITIONAL_TEMPLATE_METHOD                     __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD
388 #define __R_CONDITIONAL_FN_CALL                             __R_CONDITIONAL_NOINLINE_FN_CALL
389 #define __R_CONDITIONAL_FN_CALL_ONLY                        __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY
390 #else
391 #define __R_CONDITIONAL_METHOD                              __R_CONDITIONAL_INLINE_METHOD
392 #define __R_CONDITIONAL_TEMPLATE_METHOD                     __R_CONDITIONAL_INLINE_TEMPLATE_METHOD
393 #define __R_CONDITIONAL_FN_CALL                             __R_CONDITIONAL_INLINE_FN_CALL
394 #define __R_CONDITIONAL_FN_CALL_ONLY                        __R_CONDITIONAL_INLINE_FN_CALL_ONLY
395 #endif
396 #define __R_CONDITIONAL_FN_PARAMS                           __R_FN_PARAMS
397 #define __R_CONDITIONAL_FN_PARAMS_ONLY                      __R_FN_PARAMS_ONLY
398 // Macro call-site helpers
399 #define __R_NS_ASSEMBLE2(ri, rd)                            in##ri##diag##rd                // Differing internal namespaces eliminate ODR violations between modes
400 #define __R_NS_ASSEMBLE(ri, rd)                             __R_NS_ASSEMBLE2(ri, rd)
401 #define __R_NS_NAME                                         __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL)
402 #define __R_NS wil::details::__R_NS_NAME
403 #if (RESULT_DIAGNOSTICS_LEVEL == 1)
404 #define __R_FN(MethodName)                                  __R_NS:: MethodName <__COUNTER__>
405 #else
406 #define __R_FN(MethodName)                                  __R_NS:: MethodName
407 #endif
408 // NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases
409 //       This entire section is repeated below for fail fast (__RFF_ prefix).  For ease of editing this section, the
410 //       process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST),
411 //       (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST)
412 #define __RFF_COMMA ,
413 #define __RFF_FN_CALL_FULL                                    callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress
414 #define __RFF_FN_CALL_FULL_RA                                 callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress()
415 // The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly
416 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2)  // line number
417 #define __RFF_IF_LINE(term) term
418 #define __RFF_IF_NOT_LINE(term)
419 #define __RFF_IF_COMMA ,
420 #else
421 #define __RFF_IF_LINE(term)
422 #define __RFF_IF_NOT_LINE(term) term
423 #define __RFF_IF_COMMA
424 #endif
425 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 3) // line number + file name
426 #define __RFF_IF_FILE(term) term
427 #define __RFF_IF_NOT_FILE(term)
428 #else
429 #define __RFF_IF_FILE(term)
430 #define __RFF_IF_NOT_FILE(term) term
431 #endif
432 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 4) // line number + file name + function name
433 #define __RFF_IF_FUNCTION(term) term
434 #define __RFF_IF_NOT_FUNCTION(term)
435 #else
436 #define __RFF_IF_FUNCTION(term)
437 #define __RFF_IF_NOT_FUNCTION(term) term
438 #endif
439 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 5) // line number + file name + function name + macro code
440 #define __RFF_IF_CODE(term) term
441 #define __RFF_IF_NOT_CODE(term)
442 #else
443 #define __RFF_IF_CODE(term)
444 #define __RFF_IF_NOT_CODE(term) term
445 #endif
446 #if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1)
447 #define __RFF_IF_CALLERADDRESS(term) term
448 #define __RFF_IF_NOT_CALLERADDRESS(term)
449 #else
450 #define __RFF_IF_CALLERADDRESS(term)
451 #define __RFF_IF_NOT_CALLERADDRESS(term) term
452 #endif
453 #if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) || (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2)
454 #define __RFF_IF_TRAIL_COMMA ,
455 #else
456 #define __RFF_IF_TRAIL_COMMA
457 #endif
458 // Assemble the varying amounts of data into a single macro
459 #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)
460 #define __RFF_INFO(CODE)                                      __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA
461 #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)
462 #define __RFF_INFO_NOFILE(CODE)                               __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA
463 #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)
464 #define __RFF_FN_PARAMS                                       __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA
465 #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)
466 #define __RFF_FN_CALL                                         __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA
467 #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;)
468 #define __RFF_FN_UNREFERENCED                                 __RFF_IF_CALLERADDRESS(callerReturnAddress;) __RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;)
469 // 1) Direct Methods
470 //      * Called Directly by Macros
471 //      * Always noinline
472 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
473 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
474 #define __RFF_DIRECT_METHOD(RetType, MethodName)              template <unsigned int optimizerCounter> inline __declspec(noinline) RetType MethodName
475 #define __RFF_DIRECT_NORET_METHOD(RetType, MethodName)        template <unsigned int optimizerCounter> inline __declspec(noinline) RESULT_NORETURN RetType MethodName
476 #else
477 #define __RFF_DIRECT_METHOD(RetType, MethodName)              inline __declspec(noinline) RetType MethodName
478 #define __RFF_DIRECT_NORET_METHOD(RetType, MethodName)        inline __declspec(noinline) RESULT_NORETURN RetType MethodName
479 #endif
480 #define __RFF_DIRECT_FN_PARAMS                                __RFF_FN_PARAMS
481 #define __RFF_DIRECT_FN_PARAMS_ONLY                           __RFF_FN_PARAMS_ONLY
482 #define __RFF_DIRECT_FN_CALL                                  __RFF_FN_CALL_FULL_RA __RFF_COMMA
483 #define __RFF_DIRECT_FN_CALL_ONLY                             __RFF_FN_CALL_FULL_RA
484 // 2) Internal Methods
485 //      * Only called by Conditional routines
486 //      * '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)
487 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1)
488 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
489 #define __RFF_INTERNAL_NOINLINE_METHOD(MethodName)            inline __declspec(noinline) void MethodName
490 #define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName)      inline __declspec(noinline) RESULT_NORETURN void MethodName
491 #define __RFF_INTERNAL_INLINE_METHOD(MethodName)              template <unsigned int optimizerCounter> inline __declspec(noinline) void MethodName
492 #define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName)        template <unsigned int optimizerCounter> inline __declspec(noinline) RESULT_NORETURN void MethodName
493 #define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName)         MethodName <optimizerCounter>
494 #else
495 #define __RFF_INTERNAL_NOINLINE_METHOD(MethodName)            inline void MethodName
496 #define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName)      inline RESULT_NORETURN void MethodName
497 #define __RFF_INTERNAL_INLINE_METHOD(MethodName)              inline __declspec(noinline) void MethodName
498 #define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName)        inline __declspec(noinline) RESULT_NORETURN void MethodName
499 #define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName)         MethodName
500 #endif
501 #define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName)       MethodName
502 #define __RFF_INTERNAL_NOINLINE_FN_PARAMS                     __RFF_FN_PARAMS void* returnAddress __RFF_COMMA
503 #define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY                __RFF_FN_PARAMS void* returnAddress
504 #define __RFF_INTERNAL_NOINLINE_FN_CALL                       __RFF_FN_CALL_FULL __RFF_COMMA
505 #define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY                  __RFF_FN_CALL_FULL
506 #define __RFF_INTERNAL_INLINE_FN_PARAMS                       __RFF_FN_PARAMS
507 #define __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY                  __RFF_FN_PARAMS_ONLY
508 #define __RFF_INTERNAL_INLINE_FN_CALL                         __RFF_FN_CALL_FULL_RA __RFF_COMMA
509 #define __RFF_INTERNAL_INLINE_FN_CALL_ONLY                    __RFF_FN_CALL_FULL_RA
510 #if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0)
511 #define __RFF_INTERNAL_METHOD                                 __RFF_INTERNAL_NOINLINE_METHOD
512 #define __RFF_INTERNAL_NORET_METHOD                           __RFF_INTERNAL_NOINLINE_NORET_METHOD
513 #define __RFF_CALL_INTERNAL_METHOD                            __RFF_CALL_INTERNAL_NOINLINE_METHOD
514 #define __RFF_INTERNAL_FN_PARAMS                              __RFF_INTERNAL_NOINLINE_FN_PARAMS
515 #define __RFF_INTERNAL_FN_PARAMS_ONLY                         __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY
516 #define __RFF_INTERNAL_FN_CALL                                __RFF_INTERNAL_NOINLINE_FN_CALL
517 #define __RFF_INTERNAL_FN_CALL_ONLY                           __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY
518 #else
519 #define __RFF_INTERNAL_METHOD                                 __RFF_INTERNAL_INLINE_METHOD
520 #define __RFF_INTERNAL_NORET_METHOD                           __RFF_INTERNAL_INLINE_NORET_METHOD
521 #define __RFF_CALL_INTERNAL_METHOD                            __RFF_CALL_INTERNAL_INLINE_METHOD
522 #define __RFF_INTERNAL_FN_PARAMS                              __RFF_INTERNAL_INLINE_FN_PARAMS
523 #define __RFF_INTERNAL_FN_PARAMS_ONLY                         __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY
524 #define __RFF_INTERNAL_FN_CALL                                __RFF_INTERNAL_INLINE_FN_CALL
525 #define __RFF_INTERNAL_FN_CALL_ONLY                           __RFF_INTERNAL_INLINE_FN_CALL_ONLY
526 #endif
527 // 3) Conditional Methods
528 //      * Called Directly by Macros
529 //      * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST)
530 //      * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
531 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
532 #define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName)            template <unsigned int optimizerCounter> inline __declspec(noinline) RetType MethodName
533 #define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName)   inline __declspec(noinline) RetType MethodName
534 #define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName)              template <unsigned int optimizerCounter> __forceinline RetType MethodName
535 #define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName)     __forceinline RetType MethodName
536 #define __RFF_CONDITIONAL_PARTIAL_TEMPLATE                                unsigned int optimizerCounter __RFF_COMMA
537 #else
538 #define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName)            inline __declspec(noinline) RetType MethodName
539 #define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName)   inline __declspec(noinline) RetType MethodName
540 #define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName)              __forceinline RetType MethodName
541 #define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName)     __forceinline RetType MethodName
542 #define __RFF_CONDITIONAL_PARTIAL_TEMPLATE
543 #endif
544 #define __RFF_CONDITIONAL_NOINLINE_FN_CALL                    __RFF_FN_CALL _ReturnAddress() __RFF_COMMA
545 #define __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY               __RFF_FN_CALL _ReturnAddress()
546 #define __RFF_CONDITIONAL_INLINE_FN_CALL                      __RFF_FN_CALL
547 #define __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY                 __RFF_FN_CALL_ONLY
548 #if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0)
549 #define __RFF_CONDITIONAL_METHOD                              __RFF_CONDITIONAL_NOINLINE_METHOD
550 #define __RFF_CONDITIONAL_TEMPLATE_METHOD                     __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD
551 #define __RFF_CONDITIONAL_FN_CALL                             __RFF_CONDITIONAL_NOINLINE_FN_CALL
552 #define __RFF_CONDITIONAL_FN_CALL_ONLY                        __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY
553 #else
554 #define __RFF_CONDITIONAL_METHOD                              __RFF_CONDITIONAL_INLINE_METHOD
555 #define __RFF_CONDITIONAL_TEMPLATE_METHOD                     __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD
556 #define __RFF_CONDITIONAL_FN_CALL                             __RFF_CONDITIONAL_INLINE_FN_CALL
557 #define __RFF_CONDITIONAL_FN_CALL_ONLY                        __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY
558 #endif
559 #define __RFF_CONDITIONAL_FN_PARAMS                           __RFF_FN_PARAMS
560 #define __RFF_CONDITIONAL_FN_PARAMS_ONLY                      __RFF_FN_PARAMS_ONLY
561 // Macro call-site helpers
562 #define __RFF_NS_ASSEMBLE2(ri, rd)                            in##ri##diag##rd                // Differing internal namespaces eliminate ODR violations between modes
563 #define __RFF_NS_ASSEMBLE(ri, rd)                             __RFF_NS_ASSEMBLE2(ri, rd)
564 #define __RFF_NS_NAME                                         __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST)
565 #define __RFF_NS wil::details::__RFF_NS_NAME
566 #if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1)
567 #define __RFF_FN(MethodName)                                  __RFF_NS:: MethodName <__COUNTER__>
568 #else
569 #define __RFF_FN(MethodName)                                  __RFF_NS:: MethodName
570 #endif
571 // end-of-repeated fail-fast handling macros
572 
573 // Helpers for return macros
574 #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)
575 #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)
576 #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)
577 #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)
578 #define __RETURN_GLE_MSG_FAIL(str, fmt, ...)                 return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) fmt, ##__VA_ARGS__)
579 #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)
580 #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)
581 #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)
582 #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)
583 #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)
584 #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)
585 #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)
586 #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)
587 #define __RETURN_GLE_FAIL(str)                               return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str))
588 #define __RETURN_GLE_FAIL_NOFILE(str)                        return __R_FN(Return_GetLastError)(__R_INFO_NOFILE_ONLY(str))
589 #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)
590 #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)
591 /// @endcond
592 
593 //*****************************************************************************
594 // Macros for returning failures as HRESULTs
595 //*****************************************************************************
596 
597 // Always returns a known result (HRESULT) - always logs failures
598 #define RETURN_HR(hr)                                           __RETURN_HR(wil::verify_hresult(hr), #hr)
599 #define RETURN_LAST_ERROR()                                     __RETURN_GLE_FAIL(nullptr)
600 #define RETURN_WIN32(win32err)                                  __RETURN_WIN32(win32err, #win32err)
601 #define RETURN_NTSTATUS(status)                                 __RETURN_NTSTATUS(status, #status)
602 
603 // Conditionally returns failures (HRESULT) - always logs failures
604 #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)
605 #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)
606 #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)
607 #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)
608 #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)
609 #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)
610 #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)
611 #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)
612 #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)
613 
614 // Always returns a known failure (HRESULT) - always logs a var-arg message on failure
615 #define RETURN_HR_MSG(hr, fmt, ...)                             __RETURN_HR_MSG(wil::verify_hresult(hr), #hr, fmt, ##__VA_ARGS__)
616 #define RETURN_LAST_ERROR_MSG(fmt, ...)                         __RETURN_GLE_MSG_FAIL(nullptr, fmt, ##__VA_ARGS__)
617 #define RETURN_WIN32_MSG(win32err, fmt, ...)                    __RETURN_WIN32_MSG(win32err, #win32err, fmt, ##__VA_ARGS__)
618 #define RETURN_NTSTATUS_MSG(status, fmt, ...)                   __RETURN_NTSTATUS_MSG(status, #status, fmt, ##__VA_ARGS__)
619 
620 // Conditionally returns failures (HRESULT) - always logs a var-arg message on failure
621 #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)
622 #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)
623 #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)
624 #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)
625 #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)
626 #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)
627 #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)
628 #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)
629 #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)
630 
631 // Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern
632 #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)
633 #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)
634 #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)
635 #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)
636 #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)
637 #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)
638 #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)
639 #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)
640 #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)
641 
642 #define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e))
643 #define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \
644     do \
645     { \
646         const auto __hrRet = wil::verify_hresult(hr); \
647         if (FAILED(__hrRet)) \
648         { \
649             if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \
650             { \
651                 return __hrRet; \
652             } \
653             __RETURN_HR_FAIL(__hrRet, #hr); \
654         } \
655     } \
656     while ((void)0, 0)
657 
658 //*****************************************************************************
659 // Macros for logging failures (ignore or pass-through)
660 //*****************************************************************************
661 
662 // Always logs a known failure
663 #define LOG_HR(hr)                                              __R_FN(Log_Hr)(__R_INFO(#hr) wil::verify_hresult(hr))
664 #define LOG_LAST_ERROR()                                        __R_FN(Log_GetLastError)(__R_INFO_ONLY(nullptr))
665 #define LOG_WIN32(win32err)                                     __R_FN(Log_Win32)(__R_INFO(#win32err) win32err)
666 #define LOG_NTSTATUS(status)                                    __R_FN(Log_NtStatus)(__R_INFO(#status) status)
667 
668 // Conditionally logs failures - returns parameter value
669 #define LOG_IF_FAILED(hr)                                       __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr))
670 #define LOG_IF_WIN32_BOOL_FALSE(win32BOOL)                      __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
671 #define LOG_IF_WIN32_ERROR(win32err)                            __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err)
672 #define LOG_IF_NULL_ALLOC(ptr)                                  __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr)
673 #define LOG_HR_IF(hr, condition)                                __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
674 #define LOG_HR_IF_NULL(hr, ptr)                                 __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr)
675 #define LOG_LAST_ERROR_IF(condition)                            __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition))
676 #define LOG_LAST_ERROR_IF_NULL(ptr)                             __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr)
677 #define LOG_IF_NTSTATUS_FAILED(status)                          __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status) status)
678 
679 // Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures
680 #define SUCCEEDED_LOG(hr)                                       SUCCEEDED(LOG_IF_FAILED(hr))
681 #define FAILED_LOG(hr)                                          FAILED(LOG_IF_FAILED(hr))
682 #define SUCCEEDED_WIN32_LOG(win32err)                           SUCCEEDED_WIN32(LOG_IF_WIN32_ERROR(win32err))
683 #define FAILED_WIN32_LOG(win32err)                              FAILED_WIN32(LOG_IF_WIN32_ERROR(win32err))
684 #define SUCCEEDED_NTSTATUS_LOG(status)                          SUCCEEDED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status))
685 #define FAILED_NTSTATUS_LOG(status)                             FAILED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status))
686 
687 // Alternatives for NT_SUCCESS(x) that conditionally logs failures
688 #define NT_SUCCESS_LOG(status)                                  NT_SUCCESS(LOG_IF_NTSTATUS_FAILED(status))
689 
690 // Always logs a known failure - logs a var-arg message on failure
691 #define LOG_HR_MSG(hr, fmt, ...)                                __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
692 #define LOG_LAST_ERROR_MSG(fmt, ...)                            __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
693 #define LOG_WIN32_MSG(win32err, fmt, ...)                       __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
694 #define LOG_NTSTATUS_MSG(status, fmt, ...)                      __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__)
695 
696 // Conditionally logs failures - returns parameter value - logs a var-arg message on failure
697 #define LOG_IF_FAILED_MSG(hr, fmt, ...)                         __R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
698 #define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)        __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
699 #define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...)              __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
700 #define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...)                    __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
701 #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__)
702 #define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...)                   __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__)
703 #define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...)              __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
704 #define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)               __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
705 #define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)            __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__)
706 
707 #define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e)
708 #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__))
709 
710 //*****************************************************************************
711 // Macros to fail fast the process on failures
712 //*****************************************************************************
713 
714 // Always fail fast a known failure
715 #define FAIL_FAST_HR(hr)                                        __RFF_FN(FailFast_Hr)(__RFF_INFO(#hr) wil::verify_hresult(hr))
716 #define FAIL_FAST_LAST_ERROR()                                  __RFF_FN(FailFast_GetLastError)(__RFF_INFO_ONLY(nullptr))
717 #define FAIL_FAST_WIN32(win32err)                               __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err) win32err)
718 #define FAIL_FAST_NTSTATUS(status)                              __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status) status)
719 
720 // Conditionally fail fast failures - returns parameter value
721 #define FAIL_FAST_IF_FAILED(hr)                                 __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr))
722 #define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL)                __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
723 #define FAIL_FAST_IF_WIN32_ERROR(win32err)                      __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err)
724 #define FAIL_FAST_IF_NULL_ALLOC(ptr)                            __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr)
725 #define FAIL_FAST_HR_IF(hr, condition)                          __RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
726 #define FAIL_FAST_HR_IF_NULL(hr, ptr)                           __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr)
727 #define FAIL_FAST_LAST_ERROR_IF(condition)                      __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition))
728 #define FAIL_FAST_LAST_ERROR_IF_NULL(ptr)                       __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr)
729 #define FAIL_FAST_IF_NTSTATUS_FAILED(status)                    __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status)
730 
731 // Always fail fast a known failure - fail fast a var-arg message on failure
732 #define FAIL_FAST_HR_MSG(hr, fmt, ...)                          __RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
733 #define FAIL_FAST_LAST_ERROR_MSG(fmt, ...)                      __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) fmt, ##__VA_ARGS__)
734 #define FAIL_FAST_WIN32_MSG(win32err, fmt, ...)                 __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
735 #define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...)                __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, fmt, ##__VA_ARGS__)
736 
737 // Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure
738 #define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...)                   __RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
739 #define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)  __RFF_FN(FailFast_IfWin32BoolFalseMsg)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
740 #define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...)        __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
741 #define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...)              __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
742 #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__)
743 #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__)
744 #define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...)        __RFF_FN(FailFast_GetLastErrorIfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
745 #define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)         __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
746 #define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)      __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, fmt, ##__VA_ARGS__)
747 
748 // Always fail fast a known failure
749 #ifndef FAIL_FAST
750 #define FAIL_FAST()                                             __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(nullptr))
751 #endif
752 
753 // Conditionally fail fast failures - returns parameter value
754 #define FAIL_FAST_IF(condition)                                 __RFF_FN(FailFast_If)(__RFF_INFO(#condition) wil::verify_bool(condition))
755 #define FAIL_FAST_IF_NULL(ptr)                                  __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr)
756 
757 // Always fail fast a known failure - fail fast a var-arg message on failure
758 #define FAIL_FAST_MSG(fmt, ...)                                 __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) fmt, ##__VA_ARGS__)
759 
760 // Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure
761 #define FAIL_FAST_IF_MSG(condition, fmt, ...)                   __RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
762 #define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...)                    __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
763 
764 // Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state)
765 #define FAIL_FAST_IMMEDIATE()                                   __RFF_FN(FailFastImmediate_Unexpected)()
766 
767 // Conditional immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state)
768 #define FAIL_FAST_IMMEDIATE_IF_FAILED(hr)                       __RFF_FN(FailFastImmediate_IfFailed)(wil::verify_hresult(hr))
769 #define FAIL_FAST_IMMEDIATE_IF(condition)                       __RFF_FN(FailFastImmediate_If)(wil::verify_bool(condition))
770 #define FAIL_FAST_IMMEDIATE_IF_NULL(ptr)                        __RFF_FN(FailFastImmediate_IfNull)(ptr)
771 #define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status)          __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status)
772 
773 // Specializations
774 #define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT()              do { if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) { wil::details::g_pfnFailFastInLoaderCallout(); } } while ((void)0, 0)
775 
776 
777 //*****************************************************************************
778 // Macros to throw exceptions on failure
779 //*****************************************************************************
780 
781 #ifdef WIL_ENABLE_EXCEPTIONS
782 
783 // Always throw a known failure
784 #define THROW_HR(hr)                                            __R_FN(Throw_Hr)(__R_INFO(#hr) wil::verify_hresult(hr))
785 #define THROW_LAST_ERROR()                                      __R_FN(Throw_GetLastError)(__R_INFO_ONLY(nullptr))
786 #define THROW_WIN32(win32err)                                   __R_FN(Throw_Win32)(__R_INFO(#win32err) win32err)
787 #define THROW_EXCEPTION(exception)                              wil::details::ReportFailure_CustomException(__R_INFO(#exception) exception)
788 #define THROW_NTSTATUS(status)                                  __R_FN(Throw_NtStatus)(__R_INFO(#status) status)
789 
790 // Conditionally throw failures - returns parameter value
791 #define THROW_IF_FAILED(hr)                                     __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr))
792 #define THROW_IF_WIN32_BOOL_FALSE(win32BOOL)                    __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL))
793 #define THROW_IF_WIN32_ERROR(win32err)                          __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err)
794 #define THROW_IF_NULL_ALLOC(ptr)                                __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr)
795 #define THROW_HR_IF(hr, condition)                              __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition))
796 #define THROW_HR_IF_NULL(hr, ptr)                               __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr)
797 #define THROW_LAST_ERROR_IF(condition)                          __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition))
798 #define THROW_LAST_ERROR_IF_NULL(ptr)                           __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr)
799 #define THROW_IF_NTSTATUS_FAILED(status)                        __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status)
800 
801 // Always throw a known failure - throw a var-arg message on failure
802 #define THROW_HR_MSG(hr, fmt, ...)                              __R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
803 #define THROW_LAST_ERROR_MSG(fmt, ...)                          __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
804 #define THROW_WIN32_MSG(win32err, fmt, ...)                     __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
805 #define THROW_EXCEPTION_MSG(exception, fmt, ...)                wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, fmt, ##__VA_ARGS__)
806 #define THROW_NTSTATUS_MSG(status, fmt, ...)                    __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__)
807 
808 // Conditionally throw failures - returns parameter value - throw a var-arg message on failure
809 #define THROW_IF_FAILED_MSG(hr, fmt, ...)                       __R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__)
810 #define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...)      __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__)
811 #define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...)            __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__)
812 #define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...)                  __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
813 #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__)
814 #define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...)                 __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__)
815 #define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...)            __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__)
816 #define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...)             __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__)
817 #define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...)          __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__)
818 
819 
820 //*****************************************************************************
821 // Macros to catch and convert exceptions on failure
822 //*****************************************************************************
823 
824 // Use these macros *within* a catch (...) block to handle exceptions
825 #define RETURN_CAUGHT_EXCEPTION()                               return __R_FN(Return_CaughtException)(__R_INFO_ONLY(nullptr))
826 #define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...)                   return __R_FN(Return_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
827 #define RETURN_CAUGHT_EXCEPTION_EXPECTED()                      return wil::ResultFromCaughtException()
828 #define LOG_CAUGHT_EXCEPTION()                                  __R_FN(Log_CaughtException)(__R_INFO_ONLY(nullptr))
829 #define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...)                      __R_FN(Log_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
830 #define FAIL_FAST_CAUGHT_EXCEPTION()                            __R_FN(FailFast_CaughtException)(__R_INFO_ONLY(nullptr))
831 #define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...)                __R_FN(FailFast_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
832 #define THROW_NORMALIZED_CAUGHT_EXCEPTION()                     __R_FN(Throw_CaughtException)(__R_INFO_ONLY(nullptr))
833 #define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...)         __R_FN(Throw_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__)
834 
835 // Use these macros in place of a catch block to handle exceptions
836 #define CATCH_RETURN()                                          catch (...) { RETURN_CAUGHT_EXCEPTION(); }
837 #define CATCH_RETURN_MSG(fmt, ...)                              catch (...) { RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); }
838 #define CATCH_RETURN_EXPECTED()                                 catch (...) { RETURN_CAUGHT_EXCEPTION_EXPECTED(); }
839 #define CATCH_LOG()                                             catch (...) { LOG_CAUGHT_EXCEPTION(); }
840 // 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.
841 // 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.
842 #define CATCH_LOG_RETURN()                                      catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION(); return; }
843 #define CATCH_LOG_MSG(fmt, ...)                                 catch (...) { LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); }
844 // Likewise use CATCH_LOG_RETURN_MSG instead of CATCH_LOG_MSG in function-try blocks around destructors.
845 #define CATCH_LOG_RETURN_MSG(fmt, ...)                          catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); return; }
846 #define CATCH_FAIL_FAST()                                       catch (...) { FAIL_FAST_CAUGHT_EXCEPTION(); }
847 #define CATCH_FAIL_FAST_MSG(fmt, ...)                           catch (...) { FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); }
848 #define CATCH_THROW_NORMALIZED()                                catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION(); }
849 #define CATCH_THROW_NORMALIZED_MSG(fmt, ...)                    catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); }
850 #define CATCH_LOG_RETURN_HR(hr)                                 catch (...) { LOG_CAUGHT_EXCEPTION(); return hr; }
851 
852 #endif  // WIL_ENABLE_EXCEPTIONS
853 
854 // Use this macro to supply diagnostics information to wil::ResultFromException
855 #define WI_DIAGNOSTICS_INFO                                     wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE)
856 #define WI_DIAGNOSTICS_NAME(name)                               wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE, name)
857 
858 
859 
860 //*****************************************************************************
861 // Usage Error Macros
862 //*****************************************************************************
863 
864 #ifndef WI_USAGE_ASSERT_STOP
865 #define WI_USAGE_ASSERT_STOP(condition)                     WI_ASSERT(condition)
866 #endif
867 #ifdef RESULT_DEBUG
868 #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)
869 #define WI_USAGE_ERROR_FORWARD(msg, ...)                    do { ReportFailure_ReplaceMsg<FailureType::Log>(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0)
870 #else
871 #define WI_USAGE_ERROR(msg, ...)                            do { LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0)
872 #define WI_USAGE_ERROR_FORWARD(msg, ...)                    do { ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0)
873 #endif
874 #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)
875 #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)
876 #ifdef RESULT_DEBUG
877 #define WI_USAGE_ASSERT(condition, msg, ...)                WI_USAGE_VERIFY(condition, msg, ##__VA_ARGS__)
878 #else
879 #define WI_USAGE_ASSERT(condition, msg, ...)
880 #endif
881 
882 //*****************************************************************************
883 // Internal Error Macros - DO NOT USE - these are for internal WIL use only to reduce sizes of binaries that use WIL
884 //*****************************************************************************
885 #ifdef RESULT_DEBUG
886 #define __WIL_PRIVATE_RETURN_IF_FAILED(hr)                   RETURN_IF_FAILED(hr)
887 #define __WIL_PRIVATE_RETURN_HR_IF(hr, cond)                 RETURN_HR_IF(hr, cond)
888 #define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond)             RETURN_LAST_ERROR_IF(cond)
889 #define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL)  RETURN_IF_WIN32_BOOL_FALSE(win32BOOL)
890 #define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr)         RETURN_LAST_ERROR_IF_NULL(ptr)
891 #define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr)              RETURN_IF_NULL_ALLOC(ptr)
892 #define __WIL_PRIVATE_RETURN_LAST_ERROR()                    RETURN_LAST_ERROR()
893 #define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition)         FAIL_FAST_HR_IF(hr, condition)
894 #define __WIL_PRIVATE_FAIL_FAST_HR(hr)                       FAIL_FAST_HR(hr)
895 #define __WIL_PRIVATE_LOG_HR(hr)                             LOG_HR(hr)
896 #else
897 #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)
898 #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)
899 #define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond)             do { if (wil::verify_bool(cond)) { __RETURN_GLE_FAIL_NOFILE(#cond); }} while ((void)0, 0)
900 #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)
901 #define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr)         do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL_NOFILE(#ptr); }} while ((void)0, 0)
902 #define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr)              do { if ((ptr) == nullptr) { __RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); }} while ((void)0, 0)
903 #define __WIL_PRIVATE_RETURN_LAST_ERROR()                    __RETURN_GLE_FAIL_NOFILE(nullptr)
904 #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))
905 #define __WIL_PRIVATE_FAIL_FAST_HR(hr)                       __RFF_FN(FailFast_Hr)(__RFF_INFO_NOFILE(#hr) wil::verify_hresult(hr))
906 #define __WIL_PRIVATE_LOG_HR(hr)                             __R_FN(Log_Hr)(__R_INFO_NOFILE(#hr) wil::verify_hresult(hr))
907 #endif
908 
909 namespace wil
910 {
911     // Indicates the kind of message / failure type that was used to produce a given error
912     enum class FailureType
913     {
914         Exception,          // THROW_...
915         Return,             // RETURN_..._LOG or RETURN_..._MSG
916         Log,                // LOG_...
917         FailFast            // FAIL_FAST_...
918     };
919 
920     /** Use with functions and macros that allow customizing which kinds of exceptions are handled.
921     This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */
922     enum class SupportedExceptions
923     {
924         Default,        //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions).
925         Known,          //!< [Known] all well known exceptions (including std::exception).
926         All,            //!< [All] all exceptions, known or otherwise.
927         None,           //!< [None] no exceptions at all, an exception will fail-fast where thrown.
928         Thrown,         //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException).
929         ThrownOrAlloc   //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or std::bad_alloc.
930     };
931 
932     // Represents the call context information about a given failure
933     // No constructors, destructors or virtual members should be contained within
934     struct CallContextInfo
935     {
936         long contextId;                         // incrementing ID for this call context (unique across an individual module load within process)
937         PCSTR contextName;                      // the explicit name given to this context
938         PCWSTR contextMessage;                  // [optional] Message that can be associated with the call context
939     };
940 
941     // Represents all context information about a given failure
942     // No constructors, destructors or virtual members should be contained within
943     struct FailureInfo
944     {
945         FailureType type;
946         HRESULT hr;
947         long failureId;                         // incrementing ID for this specific failure (unique across an individual module load within process)
948         PCWSTR pszMessage;                      // Message is only present for _MSG logging (it's the Sprintf message)
949         DWORD threadId;                         // the thread this failure was originally encountered on
950         PCSTR pszCode;                          // [debug only] Capture code from the macro
951         PCSTR pszFunction;                      // [debug only] The function name
952         PCSTR pszFile;
953         unsigned int uLineNumber;
954         int cFailureCount;                      // How many failures of 'type' have been reported in this module so far
955         PCSTR pszCallContext;                   // General breakdown of the call context stack that generated this failure
956         CallContextInfo callContextOriginating; // The outermost (first seen) call context
957         CallContextInfo callContextCurrent;     // The most recently seen call context
958         PCSTR pszModule;                        // The module where the failure originated
959         void* returnAddress;                    // The return address to the point that called the macro
960         void* callerReturnAddress;              // The return address of the function that includes the macro
961     };
962 
963     //! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions.
964     //! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions as
965     //! parameters hidden behind a macro.  In some cases, the user needs to directly supply these, so this class provides
966     //! the mechanism for that.  We only use this for user-passed content as it can't be directly controlled by RESULT_DIAGNOSTICS_LEVEL
967     //! to ensure there are no ODR violations (though that variable still controls what parameters within this structure would be available).
968     struct DiagnosticsInfo
969     {
970         void* returnAddress = nullptr;
971         PCSTR file = nullptr;
972         PCSTR name = nullptr;
973         unsigned short line = 0;
974 
975         DiagnosticsInfo() = default;
976 
DiagnosticsInfoDiagnosticsInfo977         __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_) :
978             returnAddress(returnAddress_),
979             file(file_),
980             line(line_)
981         {
982         }
983 
DiagnosticsInfoDiagnosticsInfo984         __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) :
985             returnAddress(returnAddress_),
986             file(file_),
987             name(name_),
988             line(line_)
989         {
990         }
991     };
992 
993     enum class ErrorReturn
994     {
995         Auto,
996         None
997     };
998 
999     // [optionally] Plug in error logging
1000     // Note:  This callback is deprecated.  Please use SetResultTelemetryFallback for telemetry or
1001     // SetResultLoggingCallback for observation.
1002     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;
1003 
1004     // [optional]
1005     // This can be explicitly set to control whether or not error messages will be output to OutputDebugString.  It can also
1006     // be set directly from within the debugger to force console logging for debugging purposes.
1007     __declspec(selectany) bool g_fResultOutputDebugString = true;
1008 
1009     // [optionally] Allows application to specify a debugger to detect whether a debugger is present.
1010     // Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns
1011     // false.
1012     __declspec(selectany) bool(__stdcall *g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr;
1013 
1014     // [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached and ::IsDebuggerPresent returns false
1015     __declspec(selectany) bool g_fIsDebuggerPresent = false;
1016 
1017     // [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception)
1018     __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr;
1019 
1020     // [optionally] Use to configure fast fail of unknown exceptions (turn them off).
1021     __declspec(selectany) bool g_fResultFailFastUnknownExceptions = true;
1022 
1023     // [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^
1024     __declspec(selectany) bool g_fResultThrowPlatformException = true;
1025 
1026     // [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)
1027     __declspec(selectany) bool g_fResultSupportStdException = true;
1028 
1029     // [optionally] Set to true to cause a debug break to occur on a result failure
1030     __declspec(selectany) bool g_fBreakOnFailure = false;
1031 
1032     // [optionally] customize failfast behavior
1033     __declspec(selectany) bool(__stdcall *g_pfnWilFailFast)(const wil::FailureInfo& info) WI_PFN_NOEXCEPT = nullptr;
1034 
1035     /// @cond
1036     namespace details
1037     {
1038         // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function)
1039         __declspec(selectany) bool g_resultMessageCallbackSet = false;
1040 
_Ret_range_(dest,destEnd)1041         _Success_(true) _Ret_range_(dest, destEnd)
1042         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, ...)
1043         {
1044             va_list argList;
1045             va_start(argList, format);
1046             StringCchVPrintfW(dest, (destEnd - dest), format, argList);
1047             return (destEnd == dest) ? dest : (dest + wcslen(dest));
1048         }
1049     }
1050     /// @endcond
1051 
1052     // This call generates the default logging string that makes its way to OutputDebugString for
1053     // any particular failure.  This string is also used to associate a failure with a PlatformException^ which
1054     // only allows a single string to be associated with the exception.
_Out_writes_(cchDest)1055     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
1056     {
1057         // This function was lenient to empty strings at one point and some callers became dependent on this beahvior
1058         if ((cchDest == 0) || (pszDest == nullptr))
1059         {
1060             return S_OK;
1061         }
1062 
1063         pszDest[0] = L'\0';
1064 
1065         // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console
1066         // or the platform exception object if the caller desires it.
1067         if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet)
1068         {
1069             // older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be modifying
1070             g_pfnResultLoggingCallback(const_cast<FailureInfo*>(&failure), pszDest, cchDest);
1071         }
1072 
1073         // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want
1074         // it for OutputDebugString or exception message, then generate the default string.
1075         if (pszDest[0] == L'\0')
1076         {
1077             PCSTR pszType = "";
1078             switch (failure.type)
1079             {
1080             case FailureType::Exception:
1081                 pszType = "Exception";
1082                 break;
1083             case FailureType::Return:
1084                 pszType = "ReturnHr";
1085                 break;
1086             case FailureType::Log:
1087                 pszType = "LogHr";
1088                 break;
1089             case FailureType::FailFast:
1090                 pszType = "FailFast";
1091                 break;
1092             }
1093 
1094             wchar_t szErrorText[256];
1095             szErrorText[0] = L'\0';
1096             FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, failure.hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErrorText, ARRAYSIZE(szErrorText), nullptr);
1097 
1098             // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage
1099             //     %Caller_MSG [%CODE(%FUNCTION)]
1100 
1101             PWSTR dest = pszDest;
1102             PCWSTR destEnd = (pszDest + cchDest);
1103 
1104             if (failure.pszFile != nullptr)
1105             {
1106                 dest = details::LogStringPrintf(dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress);
1107             }
1108             else
1109             {
1110                 dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress);
1111             }
1112 
1113             if (failure.callerReturnAddress != nullptr)
1114             {
1115                 dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress);
1116             }
1117 
1118             dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), failure.hr, szErrorText);
1119 
1120             if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr))
1121             {
1122                 dest = details::LogStringPrintf(dest, destEnd, L"    ");
1123                 if (failure.pszMessage != nullptr)
1124                 {
1125                     dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage);
1126                 }
1127                 if (failure.pszCallContext != nullptr)
1128                 {
1129                     dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext);
1130                 }
1131 
1132                 if (failure.pszCode != nullptr)
1133                 {
1134                     dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode);
1135                 }
1136                 else if (failure.pszFunction != nullptr)
1137                 {
1138                     dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction);
1139                 }
1140                 else
1141                 {
1142                     dest = details::LogStringPrintf(dest, destEnd, L"\n");
1143                 }
1144             }
1145         }
1146 
1147         // Explicitly choosing to return success in the event of truncation... Current callers
1148         // depend upon it or it would be eliminated.
1149         return S_OK;
1150     }
1151 
1152     /// @cond
1153     namespace details
1154     {
1155         //! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context where
1156         //! exceptions or errors can be observed and logged.
1157         struct IFunctor
1158         {
1159             virtual HRESULT Run() = 0;
1160         };
1161 
1162         //! Used to provide custom behavior when an exception is encountered while executing IFunctor
1163         struct IFunctorHost
1164         {
1165             virtual HRESULT Run(IFunctor& functor) = 0;
1166             virtual HRESULT ExceptionThrown(void* returnAddress) = 0;
1167         };
1168 
1169         // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback)
1170         __declspec(selectany) void(__stdcall *g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr;
1171 
1172         // Result.h plug-in (WIL use only)
1173         __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;
1174 
1175         // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging
1176         __declspec(selectany) void(__stdcall *g_pfnLoggingCallback)(wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr;
1177 
1178         // Desktop/System Only:  Module fetch function (automatically setup)
1179         __declspec(selectany) PCSTR(__stdcall *g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr;
1180 
1181         // Desktop/System Only:  Retrieve address offset and modulename
1182         __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;
1183 
1184         // Called with the expectation that the program will terminate when called inside of a loader callout.
1185         // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
1186         __declspec(selectany) void(__stdcall *g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr;
1187 
1188         // Called to translate an NTSTATUS value to a Win32 error code
1189         // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
1190         __declspec(selectany) ULONG(__stdcall *g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr;
1191 
1192         // Desktop/System Only: Call to DebugBreak
1193         __declspec(selectany) void(__stdcall *g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr;
1194 
1195         // Called to determine whether or not termination is happening
1196         // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined)
1197         __declspec(selectany) BOOLEAN(__stdcall *g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr;
1198         __declspec(selectany) bool g_processShutdownInProgress = false;
1199 
1200         // On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules
1201         // that do not have RaiseFailFastException in kernelbase.  UWP apps will directly link.
1202         __declspec(selectany) void (__stdcall *g_pfnRaiseFailFastException)(PEXCEPTION_RECORD,PCONTEXT,DWORD) = nullptr;
1203 
1204         // Exception-based compiled additions
1205         __declspec(selectany) HRESULT(__stdcall *g_pfnRunFunctorWithExceptionFilter)(IFunctor& functor, IFunctorHost& host, void* returnAddress) = nullptr;
1206         __declspec(selectany) void(__stdcall *g_pfnRethrow)() = nullptr;
1207         __declspec(selectany) void(__stdcall *g_pfnThrowResultException)(const FailureInfo& failure) = nullptr;
1208         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;
1209 
1210         // C++/WinRT additions
1211         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;
1212 
1213         // C++/cx compiled additions
1214         extern "C" __declspec(selectany) void(__stdcall *g_pfnThrowPlatformException)(FailureInfo const &failure, PCWSTR debugString) = nullptr;
1215         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;
1216         __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromKnownExceptions_WinRt)(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) = nullptr;
1217 
1218         // Plugin to call RoOriginateError (WIL use only)
1219         __declspec(selectany) void(__stdcall *g_pfnOriginateCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr;
1220 
1221         enum class ReportFailureOptions
1222         {
1223             None                    = 0x00,
1224             ForcePlatformException  = 0x01,
1225             MayRethrow              = 0x02,
1226         };
1227         DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions);
1228 
1229         template <typename TFunctor>
1230         using functor_return_type = decltype((*static_cast<TFunctor*>(nullptr))());
1231 
1232         template <typename TFunctor>
1233         struct functor_wrapper_void : public IFunctor
1234         {
1235             TFunctor&& functor;
functor_wrapper_voidfunctor_wrapper_void1236             functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward<TFunctor>(functor_)) { }
1237             #pragma warning(push)
1238             #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2
Runfunctor_wrapper_void1239             HRESULT Run() override
1240             {
1241                 functor();
1242                 return S_OK;
1243             }
1244             #pragma warning(pop)
1245         };
1246 
1247         template <typename TFunctor>
1248         struct functor_wrapper_HRESULT : public IFunctor
1249         {
1250             TFunctor&& functor;
functor_wrapper_HRESULTfunctor_wrapper_HRESULT1251             functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward<TFunctor>(functor_)) { }
Runfunctor_wrapper_HRESULT1252             HRESULT Run() override
1253             {
1254                 return functor();
1255             }
1256         };
1257 
1258         template <typename TFunctor, typename TReturn>
1259         struct functor_wrapper_other : public IFunctor
1260         {
1261             TFunctor&& functor;
1262             TReturn& retVal;
functor_wrapper_otherfunctor_wrapper_other1263             functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward<TFunctor>(functor_)), retVal(retval_) { }
1264             #pragma warning(push)
1265             #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2
Runfunctor_wrapper_other1266             HRESULT Run() override
1267             {
1268                 retVal = functor();
1269                 return S_OK;
1270             }
1271             #pragma warning(pop)
1272         };
1273 
1274         struct tag_return_void : public wistd::integral_constant<size_t, 0>
1275         {
1276             template <typename TFunctor>
1277             using functor_wrapper = functor_wrapper_void<TFunctor>;
1278         };
1279 
1280         struct tag_return_HRESULT : public wistd::integral_constant<size_t, 1>
1281         {
1282             template <typename TFunctor>
1283             using functor_wrapper = functor_wrapper_HRESULT<TFunctor>;
1284         };
1285 
1286         struct tag_return_other : public wistd::integral_constant<size_t, 2>
1287         {
1288             template <typename TFunctor, typename TReturn>
1289             using functor_wrapper = functor_wrapper_other<TFunctor, TReturn>;
1290         };
1291 
1292         // type-trait to help discover the return type of a functor for tag/dispatch.
1293 
1294         template <ErrorReturn errorReturn, typename T>
1295         struct return_type
1296         {
1297             typedef tag_return_other type;
1298         };
1299 
1300         template <>
1301         struct return_type<ErrorReturn::Auto, HRESULT>
1302         {
1303             typedef tag_return_HRESULT type;
1304         };
1305 
1306         template <>
1307         struct return_type<ErrorReturn::Auto, void>
1308         {
1309             typedef tag_return_void type;
1310         };
1311 
1312         template <>
1313         struct return_type<ErrorReturn::None, void>
1314         {
1315             typedef tag_return_void type;
1316         };
1317 
1318         template <ErrorReturn errorReturn, typename Functor>
1319         using functor_tag = typename return_type<errorReturn, functor_return_type<Functor>>::type;
1320 
1321         // Forward declarations to enable use of fail fast and reporting internally...
1322         namespace __R_NS_NAME
1323         {
1324             _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT;
1325             _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT;
1326             _Post_satisfies_(return == err) __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT;
1327         }
1328         namespace __RFF_NS_NAME
1329         {
1330             __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT;
1331             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT;
1332             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT;
1333             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT;
1334             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT;
1335         }
1336 
1337         __declspec(noreturn) inline void __stdcall WilFailFast(const FailureInfo& info);
1338         inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message,
1339                                bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars,
1340                                _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars,
1341                                _Out_ FailureInfo *failure) WI_NOEXCEPT;
1342 
1343         __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None);
1344         template<FailureType, bool = false>
1345         __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None);
1346         template<FailureType>
1347         inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...);
1348         __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr);
1349         template<FailureType>
1350         __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr);
1351         template<FailureType>
1352         __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default);
1353 
1354         //*****************************************************************************
1355         // Fail fast helpers (for use only internally to WIL)
1356         //*****************************************************************************
1357 
1358         /// @cond
1359         #define __FAIL_FAST_ASSERT__(condition)                         do { if (!(condition)) { __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); } } while ((void)0, 0)
1360         #define __FAIL_FAST_IMMEDIATE_ASSERT__(condition)               do { if (!(condition)) { wil::FailureInfo failure {}; wil::details::WilFailFast(failure); } } while ((void)0, 0)
1361         #define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition)        __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#condition) wil::verify_BOOL(condition))
1362 
1363         // A simple ref-counted buffer class.  The interface is very similar to shared_ptr<>, only it manages
1364         // an allocated buffer and maintains the size.
1365 
1366         class shared_buffer
1367         {
1368         public:
1369             shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0)
1370             {
1371             }
1372 
1373             shared_buffer(shared_buffer const &other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0)
1374             {
1375                 assign(other.m_pCopy, other.m_size);
1376             }
1377 
1378             shared_buffer(shared_buffer &&other) WI_NOEXCEPT :
1379                 m_pCopy(other.m_pCopy),
1380                 m_size(other.m_size)
1381             {
1382                 other.m_pCopy = nullptr;
1383                 other.m_size = 0;
1384             }
1385 
1386             ~shared_buffer() WI_NOEXCEPT
1387             {
1388                 reset();
1389             }
1390 
1391             shared_buffer& operator=(shared_buffer const &other) WI_NOEXCEPT
1392             {
1393                 if (this != wistd::addressof(other))
1394                 {
1395                     assign(other.m_pCopy, other.m_size);
1396                 }
1397                 return *this;
1398             }
1399 
1400             shared_buffer& operator=(shared_buffer &&other) WI_NOEXCEPT
1401             {
1402                 if (this != wistd::addressof(other))
1403                 {
1404                     reset();
1405                     m_pCopy = other.m_pCopy;
1406                     m_size = other.m_size;
1407                     other.m_pCopy = nullptr;
1408                     other.m_size = 0;
1409                 }
1410                 return *this;
1411             }
1412 
1413             void reset() WI_NOEXCEPT
1414             {
1415                 if (m_pCopy != nullptr)
1416                 {
1417                     if (0 == ::InterlockedDecrementRelease(m_pCopy))
1418                     {
1419                         WIL_FreeMemory(m_pCopy);
1420                     }
1421                     m_pCopy = nullptr;
1422                     m_size = 0;
1423                 }
1424             }
1425 
1426             bool create(_In_reads_bytes_opt_(cbData) void const *pData, size_t cbData) WI_NOEXCEPT
1427             {
1428                 if (cbData == 0)
1429                 {
1430                     reset();
1431                     return true;
1432                 }
1433 
1434                 long *pCopyRefCount = reinterpret_cast<long *>(WIL_AllocateMemory(sizeof(long)+cbData));
1435                 if (pCopyRefCount == nullptr)
1436                 {
1437                     return false;
1438                 }
1439 
1440                 *pCopyRefCount = 0;
1441                 if (pData != nullptr)
1442                 {
1443                     memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter
1444                 }
1445                 assign(pCopyRefCount, cbData);
1446                 return true;
1447             }
1448 
1449             bool create(size_t cbData) WI_NOEXCEPT
1450             {
1451                 return create(nullptr, cbData);
1452             }
1453 
1454             void* get(_Out_opt_ size_t *pSize = nullptr) const WI_NOEXCEPT
1455             {
1456                 if (pSize != nullptr)
1457                 {
1458                     *pSize = m_size;
1459                 }
1460                 return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1);
1461             }
1462 
1463             size_t size() const WI_NOEXCEPT
1464             {
1465                 return m_size;
1466             }
1467 
1468             explicit operator bool() const WI_NOEXCEPT
1469             {
1470                 return (m_pCopy != nullptr);
1471             }
1472 
1473             bool unique() const WI_NOEXCEPT
1474             {
1475                 return ((m_pCopy != nullptr) && (*m_pCopy == 1));
1476             }
1477 
1478         private:
1479             long *m_pCopy;      // pointer to allocation: refcount + data
1480             size_t m_size;      // size of the data from m_pCopy
1481 
1482             void assign(_In_opt_ long *pCopy, size_t cbSize) WI_NOEXCEPT
1483             {
1484                 reset();
1485                 if (pCopy != nullptr)
1486                 {
1487                     m_pCopy = pCopy;
1488                     m_size = cbSize;
1489                     ::InterlockedIncrementNoFence(m_pCopy);
1490                 }
1491             }
1492         };
1493 
1494         inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void *pData, size_t countBytes) WI_NOEXCEPT
1495         {
1496             shared_buffer buffer;
1497             buffer.create(pData, countBytes);
1498             return buffer;
1499         }
1500 
1501         inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT
1502         {
1503             shared_buffer buffer;
1504             buffer.create(countBytes);
1505             return buffer;
1506         }
1507 
1508         // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is
1509         // always simply contained within (it cannot be attached or detached).
1510 
1511         template <typename object_t>
1512         class shared_object
1513         {
1514         public:
1515             shared_object() WI_NOEXCEPT : m_pCopy(nullptr)
1516             {
1517             }
1518 
1519             shared_object(shared_object const &other) WI_NOEXCEPT :
1520                 m_pCopy(other.m_pCopy)
1521             {
1522                     if (m_pCopy != nullptr)
1523                     {
1524                         ::InterlockedIncrementNoFence(&m_pCopy->m_refCount);
1525                     }
1526                 }
1527 
1528             shared_object(shared_object &&other) WI_NOEXCEPT :
1529             m_pCopy(other.m_pCopy)
1530             {
1531                 other.m_pCopy = nullptr;
1532             }
1533 
1534             ~shared_object() WI_NOEXCEPT
1535             {
1536                 reset();
1537             }
1538 
1539             shared_object& operator=(shared_object const &other) WI_NOEXCEPT
1540             {
1541                 if (this != wistd::addressof(other))
1542                 {
1543                     reset();
1544                     m_pCopy = other.m_pCopy;
1545                     if (m_pCopy != nullptr)
1546                     {
1547                         ::InterlockedIncrementNoFence(&m_pCopy->m_refCount);
1548                     }
1549                 }
1550                 return *this;
1551             }
1552 
1553             shared_object& operator=(shared_object &&other) WI_NOEXCEPT
1554             {
1555                 if (this != wistd::addressof(other))
1556                 {
1557                     reset();
1558                     m_pCopy = other.m_pCopy;
1559                     other.m_pCopy = nullptr;
1560                 }
1561                 return *this;
1562             }
1563 
1564             void reset() WI_NOEXCEPT
1565             {
1566                 if (m_pCopy != nullptr)
1567                 {
1568                     if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount))
1569                     {
1570                         delete m_pCopy;
1571                     }
1572                     m_pCopy = nullptr;
1573                 }
1574             }
1575 
1576             bool create()
1577             {
1578                 RefAndObject *pObject = new(std::nothrow) RefAndObject();
1579                 if (pObject == nullptr)
1580                 {
1581                     return false;
1582                 }
1583                 reset();
1584                 m_pCopy = pObject;
1585                 return true;
1586             }
1587 
1588             template <typename param_t>
1589             bool create(param_t &&param1)
1590             {
1591                 RefAndObject *pObject = new(std::nothrow) RefAndObject(wistd::forward<param_t>(param1));
1592                 if (pObject == nullptr)
1593                 {
1594                     return false;
1595                 }
1596                 reset();
1597                 m_pCopy = pObject;
1598                 return true;
1599             }
1600 
1601             object_t* get() const WI_NOEXCEPT
1602             {
1603                 return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object;
1604             }
1605 
1606             explicit operator bool() const WI_NOEXCEPT
1607             {
1608                 return (m_pCopy != nullptr);
1609             }
1610 
1611             bool unique() const WI_NOEXCEPT
1612             {
1613                 return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1));
1614             }
1615 
1616             object_t *operator->() const WI_NOEXCEPT
1617             {
1618                 return get();
1619             }
1620 
1621         private:
1622             struct RefAndObject
1623             {
1624                 long m_refCount;
1625                 object_t m_object;
1626 
1627                 RefAndObject() :
1628                     m_refCount(1),
1629                     m_object()
1630                 {
1631                 }
1632 
1633                 template <typename param_t>
1634                 RefAndObject(param_t &&param1) :
1635                     m_refCount(1),
1636                     m_object(wistd::forward<param_t>(param1))
1637                 {
1638                 }
1639             };
1640 
1641             RefAndObject *m_pCopy;
1642         };
1643 
1644         // The following functions are basically the same, but are kept separated to:
1645         // 1) Provide a unique count and last error code per-type
1646         // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based
1647         //      upon count of errors from a particular type, etc)
1648 
1649         __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT
1650         {
1651             static HRESULT volatile s_hrErrorLast = S_OK;
1652             static long volatile s_cErrorCount = 0;
1653             s_hrErrorLast = hr;
1654             return ::InterlockedIncrementNoFence(&s_cErrorCount);
1655         }
1656 
1657         __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT
1658         {
1659             static HRESULT volatile s_hrErrorLast = S_OK;
1660             static long volatile s_cErrorCount = 0;
1661             s_hrErrorLast = hr;
1662             return ::InterlockedIncrementNoFence(&s_cErrorCount);
1663         }
1664 
1665         __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT
1666         {
1667             static HRESULT volatile s_hrErrorLast = S_OK;
1668             static long volatile s_cErrorCount = 0;
1669             s_hrErrorLast = hr;
1670             return ::InterlockedIncrementNoFence(&s_cErrorCount);
1671         }
1672 
1673         __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT
1674         {
1675             static HRESULT volatile s_hrErrorLast = S_OK;
1676             s_hrErrorLast = hr;
1677             return 1;
1678         }
1679 
1680         inline __declspec(noreturn) void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags)
1681         {
1682             // if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.)
1683             // or via direct linkage (e.g. UWP apps), then use it.
1684             if (g_pfnRaiseFailFastException)
1685             {
1686                 g_pfnRaiseFailFastException(er, cr, flags);
1687             }
1688             // if not, as a best effort, we are just going to call the intrinsic.
1689             __fastfail(FAST_FAIL_FATAL_APP_EXIT);
1690         }
1691 
1692 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
1693         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
1694         {
1695             HMODULE hModule = nullptr;
1696             if (address && !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<PCWSTR>(address), &hModule))
1697             {
1698                 assign_to_opt_param(addressOffset, 0U);
1699                 return false;
1700             }
1701             if (addressOffset)
1702             {
1703                 *addressOffset = address ? static_cast<unsigned int>(static_cast<unsigned char*>(address) - reinterpret_cast<unsigned char *>(hModule)) : 0;
1704             }
1705             if (name)
1706             {
1707                 char modulePath[MAX_PATH];
1708                 if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath)))
1709                 {
1710                     return false;
1711                 }
1712 
1713                 PCSTR start = modulePath + strlen(modulePath);
1714                 while ((start > modulePath) && (*(start - 1) != '\\'))
1715                 {
1716                     start--;
1717                 }
1718                 StringCchCopyA(name, size, start);
1719             }
1720             return true;
1721         }
1722 
1723         inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT
1724         {
1725             static char s_szModule[64] = {};
1726             static volatile bool s_fModuleValid = false;
1727             if (!s_fModuleValid)    // Races are acceptable
1728             {
1729                 GetModuleInformation(reinterpret_cast<void*>(&RecordFailFast), nullptr, s_szModule, ARRAYSIZE(s_szModule));
1730                 s_fModuleValid = true;
1731             }
1732             return s_szModule;
1733         }
1734 
1735         inline void __stdcall DebugBreak() WI_NOEXCEPT
1736         {
1737             ::DebugBreak();
1738         }
1739 
1740         inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags)
1741         {
1742             auto k32handle = GetModuleHandleW(L"kernelbase.dll");
1743             _Analysis_assume_(k32handle != nullptr);
1744             auto pfnRaiseFailFastException = reinterpret_cast<decltype(WilDynamicLoadRaiseFailFastException)*>(GetProcAddress(k32handle, "RaiseFailFastException"));
1745             if (pfnRaiseFailFastException)
1746             {
1747                 pfnRaiseFailFastException(er, cr, flags);
1748             }
1749         }
1750 #endif  // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
1751 
1752         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
1753         {
1754             if (size > 0)
1755             {
1756                 assign_to_opt_param(buffer, '\0');
1757             }
1758             if (addressOffset)
1759             {
1760                 *addressOffset = 0;
1761             }
1762             if (g_pfnGetModuleInformation)
1763             {
1764                 return g_pfnGetModuleInformation(address, addressOffset, buffer, size);
1765             }
1766             return false;
1767         }
1768 
1769         __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT
1770         {
1771             // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb
1772             if (SUCCEEDED_NTSTATUS(status))
1773             {
1774                 // All successful status codes have only one hresult equivalent, S_OK
1775                 return S_OK;
1776             }
1777             if (status == static_cast<NTSTATUS>(STATUS_NO_MEMORY))
1778             {
1779                 // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping
1780                 return E_OUTOFMEMORY;
1781             }
1782 
1783             if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr)
1784             {
1785                 DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status);
1786 
1787                 // ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to the Win32 error codes).
1788                 // There are known instances of this bug which are unlikely to be fixed soon, and it's always possible that additional instances
1789                 // could be added in the future. In these cases, it's better to use HRESULT_FROM_NT rather than returning a meaningless error.
1790                 if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND))
1791                 {
1792                     return __HRESULT_FROM_WIN32(err);
1793                 }
1794             }
1795 
1796             return HRESULT_FROM_NT(status);
1797         }
1798 
1799         // The following set of functions all differ only based upon number of arguments.  They are unified in their handling
1800         // of data from each of the various error-handling types (fast fail, exceptions, etc.).
1801         _Post_equals_last_error_
1802         inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT
1803         {
1804             __R_FN_UNREFERENCED;
1805             auto err = ::GetLastError();
1806             if (SUCCEEDED_WIN32(err))
1807             {
1808                 // This function should only be called when GetLastError() is set to a FAILURE.
1809                 // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues:
1810                 //  1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually
1811                 //      set the last error (consult MSDN).
1812                 //  2) Your macro check against the error is not immediately after the API call.  Pushing it later can result
1813                 //      in another API call between the previous one and the check resetting the last error.
1814                 //  3) The API you're calling has a bug in it and does not accurately set the last error (there are a few
1815                 //      examples here, such as SendMessageTimeout() that don't accurately set the last error).  For these,
1816                 //      please send mail to 'wildisc' when found and work-around with win32errorhelpers.
1817 
1818                 WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected.  GetLastError() does not have an error.");
1819                 return ERROR_ASSERTION_FAILURE;
1820             }
1821             return err;
1822         }
1823 
1824         _Translates_last_error_to_HRESULT_
1825         inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT
1826         {
1827             return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL));
1828         }
1829 
1830         _Translates_last_error_to_HRESULT_
1831         inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT
1832         {
1833             __R_FN_LOCALS_FULL_RA;
1834             return GetLastErrorFailHr(__R_FN_CALL_FULL);
1835         }
1836 
1837         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
1838         {
1839             if (formatString == nullptr)
1840             {
1841                 pszDest[0] = L'\0';
1842             }
1843             else if (argList == nullptr)
1844             {
1845                 StringCchPrintfW(pszDest, cchDest, L"%hs", formatString);
1846             }
1847             else
1848             {
1849                 wchar_t szFormatWide[2048];
1850                 StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString);
1851                 StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList);
1852             }
1853         }
1854 
1855 #pragma warning(push)
1856 #pragma warning(disable:__WARNING_RETURNING_BAD_RESULT)
1857         // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using
1858         // Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled).
1859 
1860         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)
1861         {
1862             HRESULT hr = S_OK;
1863             size_t cchOriginalMax = cchMax;
1864             while (cchMax && (*psz != '\0'))
1865             {
1866                 psz++;
1867                 cchMax--;
1868             }
1869             if (cchMax == 0)
1870             {
1871                 // the string is longer than cchMax
1872                 hr = STRSAFE_E_INVALID_PARAMETER;
1873             }
1874             if (pcchLength)
1875             {
1876                 if (SUCCEEDED(hr))
1877                 {
1878                     *pcchLength = cchOriginalMax - cchMax;
1879                 }
1880                 else
1881                 {
1882                     *pcchLength = 0;
1883                 }
1884             }
1885             return hr;
1886         }
1887 
1888         _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)
1889         {
1890             HRESULT hr;
1891             if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
1892             {
1893                 hr = STRSAFE_E_INVALID_PARAMETER;
1894             }
1895             else
1896             {
1897                 hr = WilStringLengthWorkerA(psz, cchMax, pcchLength);
1898             }
1899             if (FAILED(hr) && pcchLength)
1900             {
1901                 *pcchLength = 0;
1902             }
1903             return hr;
1904         }
1905 #pragma warning(pop)
1906 
1907         _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)
1908         {
1909             HRESULT hr = S_OK;
1910             if ((cchDest == 0) || (cchDest > cchMax))
1911             {
1912                 hr = STRSAFE_E_INVALID_PARAMETER;
1913             }
1914             return hr;
1915         }
1916 
1917         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)
1918         {
1919             HRESULT hr = S_OK;
1920             int iRet;
1921             size_t cchMax;
1922             size_t cchNewDestLength = 0;
1923 
1924             // leave the last space for the null terminator
1925             cchMax = cchDest - 1;
1926 #undef STRSAFE_USE_SECURE_CRT
1927 #define STRSAFE_USE_SECURE_CRT 1
1928         #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
1929             iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList);
1930         #else
1931         #pragma warning(push)
1932         #pragma warning(disable: __WARNING_BANNED_API_USAGE)// "STRSAFE not included"
1933             iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
1934         #pragma warning(pop)
1935         #endif
1936             // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
1937 
1938             if ((iRet < 0) || (((size_t)iRet) > cchMax))
1939             {
1940                 // need to null terminate the string
1941                 pszDest += cchMax;
1942                 *pszDest = '\0';
1943 
1944                 cchNewDestLength = cchMax;
1945 
1946                 // we have truncated pszDest
1947                 hr = STRSAFE_E_INSUFFICIENT_BUFFER;
1948             }
1949             else if (((size_t)iRet) == cchMax)
1950             {
1951                 // need to null terminate the string
1952                 pszDest += cchMax;
1953                 *pszDest = '\0';
1954 
1955                 cchNewDestLength = cchMax;
1956             }
1957             else
1958             {
1959                 cchNewDestLength = (size_t)iRet;
1960             }
1961 
1962             if (pcchNewDestLength)
1963             {
1964                 *pcchNewDestLength = cchNewDestLength;
1965             }
1966 
1967             return hr;
1968         }
1969 
1970         __inline HRESULT StringCchPrintfA( _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, ...)
1971         {
1972             HRESULT hr;
1973             hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
1974             if (SUCCEEDED(hr))
1975             {
1976                 va_list argList;
1977                 va_start(argList, pszFormat);
1978                 hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, NULL, pszFormat, argList);
1979                 va_end(argList);
1980             }
1981             else if (cchDest > 0)
1982             {
1983                 *pszDest = '\0';
1984             }
1985             return hr;
1986         }
1987 
1988         _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char)))
1989         inline size_t ResultStringSize(_In_opt_ PCSTR psz)
1990             { return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); }
1991 
1992         _Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t)))
1993         inline size_t ResultStringSize(_In_opt_ PCWSTR psz)
1994             { return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); }
1995 
1996         template<typename TString>
1997         _Ret_range_(pStart, pEnd) inline unsigned char* WriteResultString(
1998             _Pre_satisfies_(pStart <= pEnd)
1999             _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_)
2000             _When_((pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0), _Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0])))
2001             unsigned char* pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, _In_opt_z_ TString pszString, _Outptr_result_maybenull_z_ TString* ppszBufferString)
2002         {
2003             // No space? Null string? Do nothing.
2004             if ((pStart == pEnd) || !pszString || !*pszString)
2005             {
2006                 assign_null_to_opt_param(ppszBufferString);
2007                 return pStart;
2008             }
2009 
2010             // Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to
2011             // the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough,
2012             // do nothing, and tell the caller nothing was written.
2013             size_t const stringSize = ResultStringSize(pszString);
2014             size_t const bufferSize = pEnd - pStart;
2015             if (bufferSize < stringSize)
2016             {
2017                 assign_null_to_opt_param(ppszBufferString);
2018                 return pStart;
2019             }
2020 
2021             memcpy_s(pStart, bufferSize, pszString, stringSize);
2022             assign_to_opt_param(ppszBufferString, reinterpret_cast<TString>(pStart));
2023             return pStart + stringSize;
2024         }
2025 
2026         _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; }
2027         _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; }
2028 
2029         template<typename TString>
2030         _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)
2031         {
2032             size_t cchLen = UntrustedStringLength(reinterpret_cast<TString>(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0]));
2033             *ppszBufferString = (cchLen > 0) ? reinterpret_cast<TString>(pStart) : nullptr;
2034             auto pReturn = min(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0])));
2035             __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd));
2036             return pReturn;
2037         }
2038     } // details namespace
2039     /// @endcond
2040 
2041     //*****************************************************************************
2042     // WIL result handling initializers
2043     //
2044     // Generally, callers do not need to manually initialize WIL. This header creates
2045     // the appropriate .CRT init section pieces through global objects to ensure that
2046     // WilInitialize... is called before DllMain or main().
2047     //
2048     // Certain binaries do not link with the CRT or do not support .CRT-section based
2049     // initializers. Those binaries must link only with other static libraries that
2050     // also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left,
2051     // and they should call one of the WilInitialize_ResultMacros_??? methods during
2052     // their initialization phase.  Skipping this initialization path is OK as well,
2053     // but results in a slightly degraded experience with result reporting.
2054     //
2055     // Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides:
2056     // - The name of the current module in wil::FailureInfo::pszModule
2057     // - The name of the returning-to module during wil\staging.h failures
2058     //*****************************************************************************
2059 
2060 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
2061     //! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. WIL will
2062     //! only use publicly documented APIs.
2063     inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse()
2064     {
2065         details::g_pfnGetModuleName        = details::GetCurrentModuleName;
2066         details::g_pfnGetModuleInformation = details::GetModuleInformation;
2067         details::g_pfnDebugBreak           = details::DebugBreak;
2068         details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException;
2069     }
2070 
2071     /// @cond
2072     namespace details
2073     {
2074 #ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS
2075 #if !defined(BUILD_WINDOWS) || defined(WIL_SUPPRESS_PRIVATE_API_USE)
2076         WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, []
2077         {
2078             ::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse();
2079             return 1;
2080         });
2081 #endif
2082 #endif
2083     }
2084     /// @endcond
2085 #else // !WINAPI_PARTITION_DESKTOP, !WINAPI_PARTITION_SYSTEM, explicitly assume these modules can direct link
2086     namespace details
2087     {
2088         WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, []
2089         {
2090             g_pfnRaiseFailFastException = ::RaiseFailFastException;
2091             return 1;
2092         });
2093     }
2094 #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
2095 
2096     //*****************************************************************************
2097     // Public Error Handling Helpers
2098     //*****************************************************************************
2099 
2100     //! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload).
2101     inline bool ProcessShutdownInProgress()
2102     {
2103         return (details::g_processShutdownInProgress || (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false));
2104     }
2105 
2106     /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down,
2107     but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll).  The hosting DLL is responsible for calling
2108     Construct() and Destroy() to manually run the constructor and destructor during DLL load & unload.
2109     Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is
2110     called as is typical. */
2111     template<class T>
2112     class manually_managed_shutdown_aware_object
2113     {
2114     public:
2115         void construct()
2116         {
2117             void* var = &m_raw;
2118             ::new(var) T();
2119         }
2120 
2121         void destroy()
2122         {
2123             if (ProcessShutdownInProgress())
2124             {
2125                 get().ProcessShutdown();
2126             }
2127             else
2128             {
2129                 (&get())->~T();
2130             }
2131         }
2132 
2133         //! Retrieves a reference to the contained object
2134         T& get() WI_NOEXCEPT
2135         {
2136             return *reinterpret_cast<T*>(&m_raw);
2137         }
2138 
2139     private:
2140         alignas(T) unsigned char m_raw[sizeof(T)];
2141     };
2142 
2143     /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down.
2144     Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is
2145     called as is typical. */
2146     template<class T>
2147     class shutdown_aware_object
2148     {
2149     public:
2150         shutdown_aware_object()
2151         {
2152             m_object.construct();
2153         }
2154 
2155         ~shutdown_aware_object()
2156         {
2157             m_object.destroy();
2158         }
2159 
2160         //! Retrieves a reference to the contained object
2161         T& get() WI_NOEXCEPT
2162         {
2163             return m_object.get();
2164         }
2165 
2166     private:
2167         manually_managed_shutdown_aware_object<T> m_object;
2168     };
2169 
2170     /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. */
2171     template<class T>
2172     class object_without_destructor_on_shutdown
2173     {
2174     public:
2175         object_without_destructor_on_shutdown()
2176         {
2177             void* var = &m_raw;
2178             ::new(var) T();
2179         }
2180 
2181         ~object_without_destructor_on_shutdown()
2182         {
2183             if (!ProcessShutdownInProgress())
2184             {
2185                 get().~T();
2186             }
2187         }
2188 
2189         //! Retrieves a reference to the contained object
2190         T& get() WI_NOEXCEPT
2191         {
2192             return *reinterpret_cast<T*>(&m_raw);
2193         }
2194 
2195     private:
2196         alignas(T) unsigned char m_raw[sizeof(T)]{};
2197     };
2198 
2199     /** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because
2200     of termination or normal unload.  Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this
2201     determination on its own without this callback.  Suppressing private APIs requires use of this. */
2202     inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved)
2203     {
2204         if (!details::g_processShutdownInProgress)
2205         {
2206             if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr))
2207             {
2208                 details::g_processShutdownInProgress = true;
2209             }
2210         }
2211     }
2212 
2213     // [optionally] Plug in fallback telemetry reporting
2214     // Normally, the callback is owned by including ResultLogging.h in the including module.  Alternatively a module
2215     // could re-route fallback telemetry to any ONE specific provider by calling this method.
2216     inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction)
2217     {
2218         // Only ONE telemetry provider can own the fallback telemetry callback.
2219         __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnTelemetryCallback == callbackFunction));
2220         details::g_pfnTelemetryCallback = callbackFunction;
2221     }
2222 
2223     // [optionally] Plug in result logging (do not use for telemetry)
2224     // This provides the ability for a module to hook all failures flowing through the system for inspection
2225     // and/or logging.
2226     inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction)
2227     {
2228         // Only ONE function can own the result logging callback
2229         __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnLoggingCallback == callbackFunction));
2230         details::g_pfnLoggingCallback = callbackFunction;
2231     }
2232 
2233     // [optionally] Plug in custom result messages
2234     // There are some purposes that require translating the full information that is known about a failure
2235     // into a message to be logged (either through the console for debugging OR as the message attached
2236     // to a Platform::Exception^).  This callback allows a module to format the string itself away from the
2237     // default.
2238     inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction)
2239     {
2240         // Only ONE function can own the result message callback
2241         __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || (g_pfnResultLoggingCallback == callbackFunction));
2242         details::g_resultMessageCallbackSet = true;
2243         g_pfnResultLoggingCallback = callbackFunction;
2244     }
2245 
2246     // [optionally] Plug in exception remapping
2247     // A module can plug a callback in using this function to setup custom exception handling to allow any
2248     // exception type to be converted into an HRESULT from exception barriers.
2249     inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction)
2250     {
2251         // Only ONE function can own the exception conversion
2252         __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) || (g_pfnResultFromCaughtException == callbackFunction));
2253         g_pfnResultFromCaughtException = callbackFunction;
2254     }
2255 
2256     // [optionally] Plug in exception remapping
2257     // This provides the ability for a module to call RoOriginateError in case of a failure.
2258     // Normally, the callback is owned by including result_originate.h in the including module.  Alternatively a module
2259     // could re-route error origination callback to its own implementation.
2260     inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction)
2261     {
2262         // Only ONE function can own the error origination callback
2263         __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnOriginateCallback == callbackFunction));
2264         details::g_pfnOriginateCallback = callbackFunction;
2265     }
2266 
2267     // A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed
2268     // on the stack or from the caller).  The storage of FailureInfo needs to copy some data internally
2269     // for lifetime purposes.
2270 
2271     class StoredFailureInfo
2272     {
2273     public:
2274         StoredFailureInfo() WI_NOEXCEPT
2275         {
2276             ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo));
2277         }
2278 
2279         StoredFailureInfo(FailureInfo const &other) WI_NOEXCEPT
2280         {
2281             SetFailureInfo(other);
2282         }
2283 
2284         FailureInfo const & GetFailureInfo() const WI_NOEXCEPT
2285         {
2286             return m_failureInfo;
2287         }
2288 
2289         void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT
2290         {
2291             m_failureInfo = failure;
2292 
2293             size_t const cbNeed = details::ResultStringSize(failure.pszMessage) +
2294                                   details::ResultStringSize(failure.pszCode) +
2295                                   details::ResultStringSize(failure.pszFunction) +
2296                                   details::ResultStringSize(failure.pszFile) +
2297                                   details::ResultStringSize(failure.pszCallContext) +
2298                                   details::ResultStringSize(failure.pszModule) +
2299                                   details::ResultStringSize(failure.callContextCurrent.contextName) +
2300                                   details::ResultStringSize(failure.callContextCurrent.contextMessage) +
2301                                   details::ResultStringSize(failure.callContextOriginating.contextName) +
2302                                   details::ResultStringSize(failure.callContextOriginating.contextMessage);
2303 
2304             if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed))
2305             {
2306                 m_spStrings.reset();
2307                 m_spStrings.create(cbNeed);
2308             }
2309 
2310             size_t cbAlloc;
2311             unsigned char *pBuffer = static_cast<unsigned char *>(m_spStrings.get(&cbAlloc));
2312             unsigned char *pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr;
2313 
2314             if (pBuffer)
2315             {
2316                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage);
2317                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode);
2318                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction);
2319                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile);
2320                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext);
2321                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule);
2322                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName);
2323                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage);
2324                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName);
2325                 pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage);
2326                 ZeroMemory(pBuffer, pBufferEnd - pBuffer);
2327             }
2328         }
2329 
2330         // Relies upon generated copy constructor and assignment operator
2331 
2332     protected:
2333         FailureInfo m_failureInfo;
2334         details::shared_buffer m_spStrings;
2335     };
2336 
2337 #if defined(WIL_ENABLE_EXCEPTIONS) || defined(WIL_FORCE_INCLUDE_RESULT_EXCEPTION)
2338 
2339     //! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx).
2340     //! This class stores all of the FailureInfo context that is available when the exception is thrown.  It's also caught by
2341     //! exception guards for automatic conversion to HRESULT.
2342     //!
2343     //! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException has been changed).
2344     class ResultException : public std::exception
2345     {
2346     public:
2347         //! Constructs a new ResultException from an existing FailureInfo.
2348         ResultException(const FailureInfo& failure) WI_NOEXCEPT :
2349             m_failure(failure)
2350         {
2351         }
2352 
2353         //! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types).
2354         ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT :
2355             m_failure(CustomExceptionFailureInfo(hr))
2356         {
2357         }
2358 
2359         //! Returns the failed HRESULT that this exception represents.
2360         _Always_(_Post_satisfies_(return < 0)) HRESULT GetErrorCode() const WI_NOEXCEPT
2361         {
2362             HRESULT const hr = m_failure.GetFailureInfo().hr;
2363             __analysis_assume(hr < 0);
2364             return hr;
2365         }
2366 
2367         //! Get a reference to the stored FailureInfo.
2368         FailureInfo const & GetFailureInfo() const WI_NOEXCEPT
2369         {
2370             return m_failure.GetFailureInfo();
2371         }
2372 
2373         //! Sets the stored FailureInfo (use primarily only when constructing custom exception types).
2374         void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT
2375         {
2376             m_failure.SetFailureInfo(failure);
2377         }
2378 
2379         //! Provides a string representing the FailureInfo from this exception.
2380         inline const char * __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override
2381         {
2382             if (!m_what)
2383             {
2384                 wchar_t message[2048];
2385                 GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo());
2386 
2387                 char messageA[1024];
2388                 wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message);
2389                 m_what.create(messageA, strlen(messageA) + sizeof(*messageA));
2390             }
2391             return static_cast<const char *>(m_what.get());
2392         }
2393 
2394         // Relies upon auto-generated copy constructor and assignment operator
2395     protected:
2396         StoredFailureInfo m_failure;                //!< The failure information for this exception
2397         mutable details::shared_buffer m_what;      //!< The on-demand generated what() string
2398 
2399         //! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types).
2400         static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT
2401         {
2402             FailureInfo fi = {};
2403             fi.type = FailureType::Exception;
2404             fi.hr = hr;
2405             return fi;
2406         }
2407     };
2408 #endif
2409 
2410 
2411     //*****************************************************************************
2412     // Public Helpers that catch -- mostly only enabled when exceptions are enabled
2413     //*****************************************************************************
2414 
2415     // ResultFromCaughtException is a function that is meant to be called from within a catch(...) block.  Internally
2416     // it re-throws and catches the exception to convert it to an HRESULT.  If an exception is of an unrecognized type
2417     // the function will fail fast.
2418     //
2419     // try
2420     // {
2421     //     // Code
2422     // }
2423     // catch (...)
2424     // {
2425     //     hr = wil::ResultFromCaughtException();
2426     // }
2427     _Always_(_Post_satisfies_(return < 0))
2428     __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT
2429     {
2430         bool isNormalized = false;
2431         HRESULT hr = S_OK;
2432         if (details::g_pfnResultFromCaughtExceptionInternal)
2433         {
2434             hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized);
2435         }
2436         if (FAILED(hr))
2437         {
2438             return hr;
2439         }
2440 
2441         // Caller bug: an unknown exception was thrown
2442         __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions);
2443         return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
2444     }
2445 
2446     //! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running under an exception context
2447     inline void RethrowCaughtException()
2448     {
2449         // We always want to rethrow the exception under normal circumstances.  Ordinarily, we could actually guarantee
2450         // this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running
2451         // dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the
2452         // runtime check without the noreturn annotation.
2453 
2454         if (details::g_pfnRethrow)
2455         {
2456             details::g_pfnRethrow();
2457         }
2458     }
2459 
2460     //! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code
2461     inline void ThrowResultException(const FailureInfo& failure)
2462     {
2463         if (details::g_pfnThrowResultException)
2464         {
2465             details::g_pfnThrowResultException(failure);
2466         }
2467     }
2468 
2469     //! @cond
2470     namespace details
2471     {
2472 #ifdef WIL_ENABLE_EXCEPTIONS
2473         //*****************************************************************************
2474         // Private helpers to catch and propagate exceptions
2475         //*****************************************************************************
2476 
2477         __declspec(noreturn) inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS)
2478         {
2479             // This is an intentional fail-fast that was caught by an exception guard with WIL.  Look back up the callstack to determine
2480             // the source of the actual exception being thrown.  The exception guard used by the calling code did not expect this
2481             // exception type to be thrown or is specifically requesting fail-fast for this class of exception.
2482 
2483             FailureInfo failure{};
2484             WilFailFast(failure);
2485         }
2486 
2487         inline void MaybeGetExceptionString(const ResultException& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
2488         {
2489             if (debugString)
2490             {
2491                 GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo());
2492             }
2493         }
2494 
2495         inline void MaybeGetExceptionString(const std::exception& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
2496         {
2497             if (debugString)
2498             {
2499                 StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what());
2500             }
2501         }
2502 
2503         inline HRESULT ResultFromKnownException(const ResultException& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
2504         {
2505             wchar_t message[2048];
2506             message[0] = L'\0';
2507             MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
2508             auto hr = exception.GetErrorCode();
2509             wil::details::ReportFailure<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message);
2510             return hr;
2511         }
2512 
2513         inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
2514         {
2515             wchar_t message[2048];
2516             message[0] = L'\0';
2517             MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
2518             constexpr auto hr = E_OUTOFMEMORY;
2519             wil::details::ReportFailure<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message);
2520             return hr;
2521         }
2522 
2523         inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
2524         {
2525             wchar_t message[2048];
2526             message[0] = L'\0';
2527             MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
2528             constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
2529             ReportFailure<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message);
2530             return hr;
2531         }
2532 
2533         inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress)
2534         {
2535             if (g_pfnResultFromCaughtException_CppWinRt)
2536             {
2537                 wchar_t message[2048];
2538                 message[0] = L'\0';
2539                 bool ignored;
2540                 auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored);
2541                 if (FAILED(hr))
2542                 {
2543                     ReportFailure<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message);
2544                     return hr;
2545                 }
2546             }
2547 
2548             // Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success
2549             return S_OK;
2550         }
2551 
2552         inline HRESULT RecognizeCaughtExceptionFromCallback(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
2553         {
2554             HRESULT hr = g_pfnResultFromCaughtException();
2555 
2556             // If we still don't know the error -- or we would like to get the debug string for the error (if possible) we
2557             // rethrow and catch std::exception.
2558 
2559             if (SUCCEEDED(hr) || debugString)
2560             {
2561                 try
2562                 {
2563                     throw;
2564                 }
2565                 catch (std::exception& exception)
2566                 {
2567                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2568                     if (SUCCEEDED(hr))
2569                     {
2570                         hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
2571                     }
2572                 }
2573                 catch (...)
2574                 {
2575                 }
2576             }
2577 
2578             return hr;
2579         }
2580 
2581 #ifdef __cplusplus_winrt
2582         inline Platform::String^ GetPlatformExceptionMessage(Platform::Exception^ exception)
2583         {
2584             struct RawExceptionData_Partial
2585             {
2586                 PCWSTR description;
2587                 PCWSTR restrictedErrorString;
2588             };
2589 
2590             auto exceptionPtr = reinterpret_cast<void*>(static_cast<::Platform::Object^>(exception));
2591             auto exceptionInfoPtr = reinterpret_cast<ULONG_PTR*>(exceptionPtr) - 1;
2592             auto partial = reinterpret_cast<RawExceptionData_Partial*>(*exceptionInfoPtr);
2593 
2594             Platform::String^ message = exception->Message;
2595 
2596             PCWSTR errorString = partial->restrictedErrorString;
2597             PCWSTR messageString = reinterpret_cast<PCWSTR>(message ? message->Data() : nullptr);
2598 
2599             // An old Platform::Exception^ bug that did not actually expose the error string out of the exception
2600             // message.  We do it by hand here if the message associated with the strong does not contain the
2601             // message that was originally attached to the string (in the fixed version it will).
2602 
2603             if ((errorString && *errorString && messageString) &&
2604                 (wcsstr(messageString, errorString) == nullptr))
2605             {
2606                 return ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(errorString));
2607             }
2608             return message;
2609         }
2610 
2611         inline void MaybeGetExceptionString(_In_ Platform::Exception^ exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
2612         {
2613             if (debugString)
2614             {
2615                 auto message = GetPlatformExceptionMessage(exception);
2616                 auto messageString = !message ? L"(null Message)" : reinterpret_cast<PCWSTR>(message->Data());
2617                 StringCchPrintfW(debugString, debugStringChars, L"Platform::Exception^: %ws", messageString);
2618             }
2619         }
2620 
2621         inline HRESULT ResultFromKnownException(Platform::Exception^ exception, const DiagnosticsInfo& diagnostics, void* returnAddress)
2622         {
2623             wchar_t message[2048];
2624             message[0] = L'\0';
2625             MaybeGetExceptionString(exception, message, ARRAYSIZE(message));
2626             auto hr = exception->HResult;
2627             wil::details::ReportFailure<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message);
2628             return hr;
2629         }
2630 
2631         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
2632         {
2633             if (g_pfnResultFromCaughtException)
2634             {
2635                 try
2636                 {
2637                     throw;
2638                 }
2639                 catch (const ResultException& exception)
2640                 {
2641                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2642                     return exception.GetErrorCode();
2643                 }
2644                 catch (Platform::Exception^ exception)
2645                 {
2646                     *isNormalized = true;
2647                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2648                     return exception->HResult;
2649                 }
2650                 catch (const std::bad_alloc& exception)
2651                 {
2652                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2653                     return E_OUTOFMEMORY;
2654                 }
2655                 catch (...)
2656                 {
2657                     auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
2658                     if (FAILED(hr))
2659                     {
2660                         return hr;
2661                     }
2662                 }
2663             }
2664             else
2665             {
2666                 try
2667                 {
2668                     throw;
2669                 }
2670                 catch (const ResultException& exception)
2671                 {
2672                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2673                     return exception.GetErrorCode();
2674                 }
2675                 catch (Platform::Exception^ exception)
2676                 {
2677                     *isNormalized = true;
2678                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2679                     return exception->HResult;
2680                 }
2681                 catch (const std::bad_alloc& exception)
2682                 {
2683                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2684                     return E_OUTOFMEMORY;
2685                 }
2686                 catch (std::exception& exception)
2687                 {
2688                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2689                     return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
2690                 }
2691                 catch (...)
2692                 {
2693                     // Fall through to returning 'S_OK' below
2694                 }
2695             }
2696 
2697             // Tell the caller that we were unable to map the exception by succeeding...
2698             return S_OK;
2699         }
2700 
2701         // WinRT supporting version to execute a functor and catch known exceptions.
2702         inline HRESULT __stdcall ResultFromKnownExceptions_WinRt(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor)
2703         {
2704             WI_ASSERT(supported != SupportedExceptions::Default);
2705 
2706             switch (supported)
2707             {
2708             case SupportedExceptions::Known:
2709                 try
2710                 {
2711                     return functor.Run();
2712                 }
2713                 catch (const ResultException& exception)
2714                 {
2715                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2716                 }
2717                 catch (Platform::Exception^ exception)
2718                 {
2719                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2720                 }
2721                 catch (const std::bad_alloc& exception)
2722                 {
2723                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2724                 }
2725                 catch (std::exception& exception)
2726                 {
2727                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2728                 }
2729                 catch (...)
2730                 {
2731                     auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress);
2732                     if (FAILED(hr))
2733                     {
2734                         return hr;
2735                     }
2736 
2737                     // Unknown exception
2738                     throw;
2739                 }
2740                 break;
2741 
2742             case SupportedExceptions::ThrownOrAlloc:
2743                 try
2744                 {
2745                     return functor.Run();
2746                 }
2747                 catch (const ResultException& exception)
2748                 {
2749                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2750                 }
2751                 catch (Platform::Exception^ exception)
2752                 {
2753                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2754                 }
2755                 catch (const std::bad_alloc& exception)
2756                 {
2757                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2758                 }
2759                 break;
2760 
2761             case SupportedExceptions::Thrown:
2762                 try
2763                 {
2764                     return functor.Run();
2765                 }
2766                 catch (const ResultException& exception)
2767                 {
2768                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2769                 }
2770                 catch (Platform::Exception^ exception)
2771                 {
2772                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2773                 }
2774                 break;
2775             }
2776 
2777             WI_ASSERT(false);
2778             return S_OK;
2779         }
2780 
2781         inline void __stdcall ThrowPlatformException(FailureInfo const &failure, LPCWSTR debugString)
2782         {
2783             throw Platform::Exception::CreateException(failure.hr, ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(debugString)));
2784         }
2785 
2786 #if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS)
2787         WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRt, []
2788         {
2789             g_pfnResultFromCaughtException_WinRt = ResultFromCaughtException_WinRt;
2790             g_pfnResultFromKnownExceptions_WinRt = ResultFromKnownExceptions_WinRt;
2791             g_pfnThrowPlatformException = ThrowPlatformException;
2792             return 1;
2793         });
2794 #endif
2795 #endif
2796 
2797         inline void __stdcall Rethrow()
2798         {
2799             throw;
2800         }
2801 
2802         inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure)
2803         {
2804             throw ResultException(failure);
2805         }
2806 
2807         __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
2808         {
2809             if (debugString)
2810             {
2811                 *debugString = L'\0';
2812             }
2813             *isNormalized = false;
2814 
2815             if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr)
2816             {
2817                 RETURN_IF_FAILED_EXPECTED(details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized));
2818             }
2819 
2820             if (details::g_pfnResultFromCaughtException_WinRt != nullptr)
2821             {
2822                 return details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized);
2823             }
2824 
2825             if (g_pfnResultFromCaughtException)
2826             {
2827                 try
2828                 {
2829                     throw;
2830                 }
2831                 catch (const ResultException& exception)
2832                 {
2833                     *isNormalized = true;
2834                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2835                     return exception.GetErrorCode();
2836                 }
2837                 catch (const std::bad_alloc& exception)
2838                 {
2839                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2840                     return E_OUTOFMEMORY;
2841                 }
2842                 catch (...)
2843                 {
2844                     auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
2845                     if (FAILED(hr))
2846                     {
2847                         return hr;
2848                     }
2849                 }
2850             }
2851             else
2852             {
2853                 try
2854                 {
2855                     throw;
2856                 }
2857                 catch (const ResultException& exception)
2858                 {
2859                     *isNormalized = true;
2860                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2861                     return exception.GetErrorCode();
2862                 }
2863                 catch (const std::bad_alloc& exception)
2864                 {
2865                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2866                     return E_OUTOFMEMORY;
2867                 }
2868                 catch (std::exception& exception)
2869                 {
2870                     MaybeGetExceptionString(exception, debugString, debugStringChars);
2871                     return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
2872                 }
2873                 catch (...)
2874                 {
2875                     // Fall through to returning 'S_OK' below
2876                 }
2877             }
2878 
2879             // Tell the caller that we were unable to map the exception by succeeding...
2880             return S_OK;
2881         }
2882 
2883         // Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and returning
2884         // that HRESULT.  Does NOT attempt to catch unknown exceptions (which propagate).  Primarily used by SEH exception
2885         // handling techniques to stop at the point the exception is thrown.
2886         inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor)
2887         {
2888             if (supported == SupportedExceptions::Default)
2889             {
2890                 supported = g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc;
2891             }
2892 
2893             if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) &&
2894                 ((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) || (supported == SupportedExceptions::ThrownOrAlloc)))
2895             {
2896                 return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor);
2897             }
2898 
2899             switch (supported)
2900             {
2901             case SupportedExceptions::Known:
2902                 try
2903                 {
2904                     return functor.Run();
2905                 }
2906                 catch (const ResultException& exception)
2907                 {
2908                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2909                 }
2910                 catch (const std::bad_alloc& exception)
2911                 {
2912                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2913                 }
2914                 catch (std::exception& exception)
2915                 {
2916                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2917                 }
2918                 catch (...)
2919                 {
2920                     auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress);
2921                     if (FAILED(hr))
2922                     {
2923                         return hr;
2924                     }
2925 
2926                     // Unknown exception
2927                     throw;
2928                 }
2929 
2930             case SupportedExceptions::ThrownOrAlloc:
2931                 try
2932                 {
2933                     return functor.Run();
2934                 }
2935                 catch (const ResultException& exception)
2936                 {
2937                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2938                 }
2939                 catch (const std::bad_alloc& exception)
2940                 {
2941                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2942                 }
2943 
2944             case SupportedExceptions::Thrown:
2945                 try
2946                 {
2947                     return functor.Run();
2948                 }
2949                 catch (const ResultException& exception)
2950                 {
2951                     return ResultFromKnownException(exception, diagnostics, returnAddress);
2952                 }
2953 
2954             case SupportedExceptions::All:
2955                 try
2956                 {
2957                     return functor.Run();
2958                 }
2959                 catch (...)
2960                 {
2961                     return wil::details::ReportFailure_CaughtException<FailureType::Log>(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported);
2962                 }
2963 
2964             case SupportedExceptions::None:
2965                 return functor.Run();
2966 
2967             case SupportedExceptions::Default:
2968                 WI_ASSERT(false);
2969             }
2970 
2971             WI_ASSERT(false);
2972             return S_OK;
2973         }
2974 
2975         inline HRESULT ResultFromExceptionSeh(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
2976         {
2977             __try
2978             {
2979                 return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor);
2980             }
2981             __except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH)
2982             {
2983                 WI_ASSERT(false);
2984             }
2985         }
2986 
2987         __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
2988         {
2989 #ifdef RESULT_DEBUG
2990             // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions
2991             // themselves or if the caller doesn't want to fail-fast unknown exceptions
2992             if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions)
2993             {
2994                 return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor);
2995             }
2996 #endif
2997             try
2998             {
2999                 return functor.Run();
3000             }
3001             catch (...)
3002             {
3003                 return wil::details::ReportFailure_CaughtException<FailureType::Log>(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), supported);
3004             }
3005         }
3006 
3007         __declspec(noinline) inline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT
3008         {
3009             return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor);
3010         }
3011 
3012         // Exception guard -- catch exceptions and log them (or handle them with a custom callback)
3013         // WARNING: may throw an exception...
3014         inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor& functor, IFunctorHost& host, void* returnAddress)
3015         {
3016             try
3017             {
3018                 return host.Run(functor);
3019             }
3020             catch (...)
3021             {
3022                 // Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the exception or
3023                 // return the remapped failure.
3024                 return host.ExceptionThrown(returnAddress);
3025             }
3026         }
3027 
3028         WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultExceptions, []
3029         {
3030             g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter;
3031             g_pfnRethrow = Rethrow;
3032             g_pfnThrowResultException = ThrowResultExceptionInternal;
3033             g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal;
3034             return 1;
3035         });
3036 
3037     }
3038 
3039     //! A lambda-based exception guard that can vary the supported exception types.
3040     //! This function accepts a lambda and diagnostics information as its parameters and executes that lambda
3041     //! under a try/catch(...) block.  All exceptions are caught and the function reports the exception information
3042     //! and diagnostics to telemetry on failure.  An HRESULT is returned that maps to the exception.
3043     //!
3044     //! Note that an overload exists that does not report failures to telemetry at all.  This version should be preferred
3045     //! to that version.  Also note that neither of these versions are preferred over using try catch blocks to accomplish
3046     //! the same thing as they will be more efficient.
3047     //!
3048     //! See @ref page_exception_guards for more information and examples on exception guards.
3049     //! ~~~~
3050     //! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&]
3051     //! {
3052     //!     // exception-based code
3053     //!     // telemetry is reported with full exception information
3054     //! });
3055     //! ~~~~
3056     //! @param diagnostics  Always pass WI_DIAGNOSTICS_INFO as the first parameter
3057     //! @param supported    What kind of exceptions you want to support
3058     //! @param functor      A lambda that accepts no parameters; any return value is ignored
3059     //! @return             S_OK on success (no exception thrown) or an error based upon the exception thrown
3060     template <typename Functor>
3061     __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT
3062     {
3063         static_assert(details::functor_tag<ErrorReturn::None, Functor>::value != details::tag_return_other::value, "Functor must return void or HRESULT");
3064         typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(wistd::forward<Functor>(functor));
3065 
3066         return wil::details::ResultFromException(diagnostics, supported, functorObject);
3067     }
3068 
3069     //! A lambda-based exception guard.
3070     //! This overload uses SupportedExceptions::Known by default.  See @ref ResultFromException for more detailed information.
3071     template <typename Functor>
3072     __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
3073     {
3074         return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward<Functor>(functor));
3075     }
3076 
3077     //! A lambda-based exception guard that does not report failures to telemetry.
3078     //! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block.
3079     //! All exceptions are caught and the function returns an HRESULT mapping to the exception.
3080     //!
3081     //! This version (taking only a lambda) does not report failures to telemetry.  An overload with the same name
3082     //! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter
3083     //! to report failure information to telemetry.
3084     //!
3085     //! See @ref page_exception_guards for more information and examples on exception guards.
3086     //! ~~~~
3087     //! hr = wil::ResultFromException([&]
3088     //! {
3089     //!     // exception-based code
3090     //!     // the conversion of exception to HRESULT doesn't report telemetry
3091     //! });
3092     //!
3093     //! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&]
3094     //! {
3095     //!     // exception-based code
3096     //!     // telemetry is reported with full exception information
3097     //! });
3098     //! ~~~~
3099     //! @param functor  A lambda that accepts no parameters; any return value is ignored
3100     //! @return         S_OK on success (no exception thrown) or an error based upon the exception thrown
3101     template <typename Functor>
3102     inline HRESULT ResultFromException(Functor&& functor) WI_NOEXCEPT try
3103     {
3104         static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
3105         typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(wistd::forward<Functor>(functor));
3106 
3107         functorObject.Run();
3108         return S_OK;
3109     }
3110     catch (...)
3111     {
3112         return ResultFromCaughtException();
3113     }
3114 
3115 
3116     //! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported exception types.
3117     //! Functionally this is nearly identical to the corresponding @ref ResultFromException function with the exception
3118     //! that it utilizes structured exception handling internally to be able to terminate at the point where a unknown
3119     //! exception is thrown, rather than after that unknown exception has been unwound.  Though less efficient, this leads
3120     //! to a better debugging experience when analyzing unknown exceptions.
3121     //!
3122     //! For example:
3123     //! ~~~~
3124     //! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&]
3125     //! {
3126     //!     FunctionWhichMayThrow();
3127     //! });
3128     //! ~~~~
3129     //! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`.  This ends up
3130     //! throwing a `long` as an exception object which is not what the caller intended.  The normal @ref ResultFromException
3131     //! would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() is already off of the
3132     //! stack and has been unwound.  Because SEH is used for ResultFromExceptionDebug, the fail-fast occurs with everything
3133     //! leading up to and including the `throw INVALIDARG;` still on the stack (and easily debuggable).
3134     //!
3135     //! The penalty paid for using this, however, is efficiency.  It's far less efficient as a general pattern than either
3136     //! using ResultFromException directly or especially using try with CATCH_ macros directly.  Still it's helpful to deploy
3137     //! selectively to isolate issues a component may be having with unknown/unhandled exceptions.
3138     //!
3139     //! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected
3140     //! exceptions not falling into the supported category easily through fail-fast.  For example, by not supporting any
3141     //! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the point
3142     //! the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be tracked down.
3143     //!
3144     //! Also see @ref ResultFromExceptionDebugNoStdException.  It functions almost identically, but also will fail-fast and stop
3145     //! on std::exception based exceptions (but not Platform::Exception^ or wil::ResultException).  Using this can help isolate
3146     //! where an unexpected exception is being generated from.
3147     //! @param diagnostics  Always pass WI_DIAGNOSTICS_INFO as the first parameter
3148     //! @param supported    What kind of exceptions you want to support
3149     //! @param functor      A lambda that accepts no parameters; any return value is ignored
3150     //! @return             S_OK on success (no exception thrown) or an error based upon the exception thrown
3151     template <typename Functor>
3152     __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT
3153     {
3154         static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
3155         typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(wistd::forward<Functor>(functor));
3156 
3157         return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject);
3158     }
3159 
3160     //! A lambda-based exception guard that can identify the origin of unknown exceptions.
3161     //! This overload uses SupportedExceptions::Known by default.  See @ref ResultFromExceptionDebug for more detailed information.
3162     template <typename Functor>
3163     __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
3164     {
3165         static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
3166         typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(wistd::forward<Functor>(functor));
3167 
3168         return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject);
3169     }
3170 
3171     //! A fail-fast based exception guard.
3172     //! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default.  Any uncaught
3173     //! exception that makes it back to this guard would result in a fail-fast at the point the exception is thrown.
3174     template <typename Functor>
3175     __forceinline void FailFastException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT
3176     {
3177         static_assert(details::functor_tag<ErrorReturn::None, Functor>::value == details::tag_return_void::value, "Functor must return void");
3178         typename details::functor_tag<ErrorReturn::None, Functor>::template functor_wrapper<Functor> functorObject(wistd::forward<Functor>(functor));
3179 
3180         wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject);
3181     }
3182 
3183     namespace details {
3184 
3185 #endif  // WIL_ENABLE_EXCEPTIONS
3186 
3187         // Exception guard -- catch exceptions and log them (or handle them with a custom callback)
3188         // WARNING: may throw an exception...
3189         inline __declspec(noinline) HRESULT RunFunctor(IFunctor& functor, IFunctorHost& host)
3190         {
3191             if (g_pfnRunFunctorWithExceptionFilter)
3192             {
3193                 return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress());
3194             }
3195 
3196             return host.Run(functor);
3197         }
3198 
3199         // Returns true if a debugger should be considered to be connected.
3200         // Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging),
3201         // they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging),
3202         // and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call
3203         inline bool IsDebuggerPresent()
3204         {
3205             return g_fIsDebuggerPresent || ((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE));
3206         }
3207 
3208         //*****************************************************************************
3209         // Shared Reporting -- all reporting macros bubble up through this codepath
3210         //*****************************************************************************
3211 
3212         inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message,
3213             bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars,
3214             _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars,
3215             _Out_ FailureInfo *failure) WI_NOEXCEPT
3216         {
3217             debugString[0] = L'\0';
3218             callContextString[0] = L'\0';
3219 
3220             static long volatile s_failureId = 0;
3221 
3222             int failureCount = 0;
3223             switch (type)
3224             {
3225             case FailureType::Exception:
3226                 failureCount = RecordException(hr);
3227                 break;
3228             case FailureType::Return:
3229                 failureCount = RecordReturn(hr);
3230                 break;
3231             case FailureType::Log:
3232                 if (SUCCEEDED(hr))
3233                 {
3234                     // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log success
3235                     // using one of the WIL macros.  Example:
3236                     //      LOG_HR(S_OK);
3237                     // Instead, use one of the forms that conditionally logs based upon the error condition:
3238                     //      LOG_IF_FAILED(hr);
3239 
3240                     WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected.  Do not LOG_XXX success.");
3241                     hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE);
3242                 }
3243                 failureCount = RecordLog(hr);
3244                 break;
3245             case FailureType::FailFast:
3246                 failureCount = RecordFailFast(hr);
3247                 break;
3248             };
3249 
3250             failure->type = type;
3251             failure->hr = hr;
3252             failure->failureId = ::InterlockedIncrementNoFence(&s_failureId);
3253             failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr;
3254             failure->threadId = ::GetCurrentThreadId();
3255             failure->pszFile = fileName;
3256             failure->uLineNumber = lineNumber;
3257             failure->cFailureCount = failureCount;
3258             failure->pszCode = code;
3259             failure->pszFunction = functionName;
3260             failure->returnAddress = returnAddress;
3261             failure->callerReturnAddress = callerReturnAddress;
3262             failure->pszCallContext = nullptr;
3263             ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent));
3264             ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating));
3265             failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr;
3266 
3267             // Completes filling out failure, notifies thread-based callbacks and the telemetry callback
3268             if (details::g_pfnGetContextAndNotifyFailure)
3269             {
3270                 details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars);
3271             }
3272 
3273             // Allow hooks to inspect the failure before acting upon it
3274             if (details::g_pfnLoggingCallback)
3275             {
3276                 details::g_pfnLoggingCallback(*failure);
3277             }
3278 
3279             // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience
3280             // for uncaught exceptions.
3281             if (details::g_pfnOriginateCallback)
3282             {
3283                 details::g_pfnOriginateCallback(*failure);
3284             }
3285 
3286             if (SUCCEEDED(failure->hr))
3287             {
3288                 // Caller bug: Leaking a success code into a failure-only function
3289                 FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast);
3290                 failure->hr = E_UNEXPECTED;
3291             }
3292 
3293             bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString;
3294 
3295             // We need to generate the logging message if:
3296             // * We're logging to OutputDebugString
3297             // * OR the caller asked us to (generally for attaching to a C++/CX exception)
3298             if (fWantDebugString || fUseOutputDebugString)
3299             {
3300                 // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console
3301                 // or the platform exception object if the caller desires it.
3302                 if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
3303                 {
3304                     g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars);
3305                 }
3306 
3307                 // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want
3308                 // it for OutputDebugString or exception message, then generate the default string.
3309                 if (debugString[0] == L'\0')
3310                 {
3311                     GetFailureLogString(debugString, debugStringSizeChars, *failure);
3312                 }
3313 
3314                 if (fUseOutputDebugString)
3315                 {
3316                     ::OutputDebugStringW(debugString);
3317                 }
3318             }
3319             else
3320             {
3321                 // [deprecated behavior]
3322                 // This callback was at one point *always* called for all failures, so we continue to call it for failures even when we don't
3323                 // need to generate the debug string information (when the callback was supplied directly).  We can avoid this if the caller
3324                 // used the explicit function (through g_resultMessageCallbackSet)
3325                 if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet)
3326                 {
3327                     g_pfnResultLoggingCallback(failure, nullptr, 0);
3328                 }
3329             }
3330 
3331             if (g_fBreakOnFailure && (g_pfnDebugBreak != nullptr))
3332             {
3333                 g_pfnDebugBreak();
3334             }
3335         }
3336 
3337         inline __declspec(noreturn) void __stdcall WilFailFast(const wil::FailureInfo& failure)
3338         {
3339             if (g_pfnWilFailFast)
3340             {
3341                 g_pfnWilFailFast(failure);
3342             }
3343 
3344 #ifdef RESULT_RAISE_FAST_FAIL_EXCEPTION
3345             // Use of this macro is an ODR violation - use the callback instead.  This will be removed soon.
3346             RESULT_RAISE_FAST_FAIL_EXCEPTION;
3347 #endif
3348 
3349             // parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT)
3350             EXCEPTION_RECORD er{};
3351             er.NumberParameters = 1;            // default to be safe, see below
3352             er.ExceptionCode = static_cast<DWORD>(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409
3353             er.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
3354             er.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w
3355             if (failure.returnAddress == 0)                     // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it
3356             {
3357                 // passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing
3358                 // !analyze functionality to crawl the stack looking for the HRESULT
3359                 // don't pass a 0 HRESULT in param 1 because that will result in worse bucketing.
3360                 WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
3361             }
3362             else                                                // use FailureInfo caller address
3363             {
3364                 // parameter 1 is the failing HRESULT
3365                 // 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
3366                 // exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps.
3367                 er.NumberParameters = 3;
3368                 er.ExceptionInformation[1] = failure.hr;
3369                 er.ExceptionInformation[2] = failure.uLineNumber;
3370                 er.ExceptionAddress = failure.returnAddress;
3371                 WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */);
3372             }
3373         }
3374 
3375         template<FailureType T>
3376         inline __declspec(noinline) void ReportFailureBaseReturn(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options)
3377         {
3378             bool needPlatformException = ((T == FailureType::Exception) &&
3379                 WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) &&
3380                 (g_pfnThrowPlatformException != nullptr) &&
3381                 (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException)));
3382 
3383             FailureInfo failure;
3384             wchar_t debugString[2048];
3385             char callContextString[1024];
3386 
3387             LogFailure(__R_FN_CALL_FULL, T, hr, message, needPlatformException,
3388                 debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure);
3389         }
3390 
3391         template<FailureType T, bool SuppressAction>
3392         inline __declspec(noinline) void ReportFailure(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options)
3393         {
3394             ReportFailureBaseReturn<T>(__R_FN_CALL_FULL, hr, message, options);
3395         }
3396 
3397         template<FailureType T>
3398         inline __declspec(noinline) RESULT_NORETURN void ReportFailureBaseNoReturn(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options)
3399         {
3400             bool needPlatformException = ((T == FailureType::Exception) &&
3401                 WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) &&
3402                 (g_pfnThrowPlatformException != nullptr) &&
3403                 (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException)));
3404 
3405             FailureInfo failure;
3406             wchar_t debugString[2048];
3407             char callContextString[1024];
3408 
3409             LogFailure(__R_FN_CALL_FULL, T, hr, message, needPlatformException,
3410                 debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure);
3411 __WI_SUPPRESS_4127_S
3412             if (T == FailureType::FailFast)
3413             {
3414                 WilFailFast(const_cast<FailureInfo&>(failure));
3415             }
3416             else
3417             {
3418                 if (needPlatformException)
3419                 {
3420                     g_pfnThrowPlatformException(failure, debugString);
3421                 }
3422 
3423                 if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow))
3424                 {
3425                     RethrowCaughtException();
3426                 }
3427 
3428                 ThrowResultException(failure);
3429 
3430                 // Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup)
3431                 WilFailFast(const_cast<FailureInfo&>(failure));
3432             }
3433 __WI_SUPPRESS_4127_E
3434         }
3435 
3436         template<>
3437         inline __declspec(noinline) RESULT_NORETURN void ReportFailure<FailureType::FailFast, false>(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options)
3438         {
3439             ReportFailureBaseNoReturn<FailureType::FailFast>(__R_FN_CALL_FULL, hr, message, options);
3440         }
3441 
3442         template<>
3443         inline __declspec(noinline) RESULT_NORETURN void ReportFailure<FailureType::Exception, false>(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options)
3444         {
3445             ReportFailureBaseNoReturn<FailureType::Exception>(__R_FN_CALL_FULL, hr, message, options);
3446         }
3447 
3448         __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, ReportFailureOptions options)
3449         {
3450             switch(type)
3451             {
3452             case FailureType::Exception:
3453                 ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr, message, options);
3454                 break;
3455             case FailureType::FailFast:
3456                 ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr, message, options);
3457                 break;
3458             case FailureType::Log:
3459                 ReportFailure<FailureType::Log>(__R_FN_CALL_FULL, hr, message, options);
3460                 break;
3461             case FailureType::Return:
3462                 ReportFailure<FailureType::Return>(__R_FN_CALL_FULL, hr, message, options);
3463                 break;
3464             }
3465         }
3466 
3467         template<FailureType T>
3468         inline HRESULT ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported)
3469         {
3470             bool isNormalized = false;
3471             auto length = wcslen(debugString);
3472             WI_ASSERT(length < debugStringChars);
3473             HRESULT hr = S_OK;
3474             if (details::g_pfnResultFromCaughtExceptionInternal)
3475             {
3476                 hr = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized);
3477             }
3478 
3479             const bool known = (FAILED(hr));
3480             if (!known)
3481             {
3482                 hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
3483             }
3484 
3485             ReportFailureOptions options = ReportFailureOptions::ForcePlatformException;
3486             WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized);
3487 
3488             if ((supported == SupportedExceptions::None) ||
3489                 ((supported == SupportedExceptions::Known) && !known) ||
3490                 ((supported == SupportedExceptions::Thrown) && !isNormalized) ||
3491                 ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions))
3492             {
3493                 // By default WIL will issue a fail fast for unrecognized exception types.  Wil recognizes any std::exception or wil::ResultException based
3494                 // types and Platform::Exception^, so there aren't too many valid exception types which could cause this.  Those that are valid, should be handled
3495                 // by remapping the exception callback.  Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;').
3496                 // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions).
3497                 ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr, debugString, options);
3498             }
3499             else
3500             {
3501                 ReportFailure<T>(__R_FN_CALL_FULL, hr, debugString, options);
3502             }
3503 
3504             return hr;
3505         }
3506 
3507         template<FailureType T>
3508         inline HRESULT RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported)
3509         {
3510             bool isNormalized = false;
3511             const auto length = wcslen(debugString);
3512             WI_ASSERT(length < debugStringChars);
3513             HRESULT hr = S_OK;
3514             if (details::g_pfnResultFromCaughtExceptionInternal)
3515             {
3516                 hr = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized);
3517             }
3518 
3519             const bool known = (FAILED(hr));
3520             if (!known)
3521             {
3522                 hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
3523             }
3524 
3525             ReportFailureOptions options = ReportFailureOptions::ForcePlatformException;
3526             WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized);
3527 
3528             if ((supported == SupportedExceptions::None) ||
3529                 ((supported == SupportedExceptions::Known) && !known) ||
3530                 ((supported == SupportedExceptions::Thrown) && !isNormalized) ||
3531                 ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions))
3532             {
3533                 // By default WIL will issue a fail fast for unrecognized exception types.  Wil recognizes any std::exception or wil::ResultException based
3534                 // types and Platform::Exception^, so there aren't too many valid exception types which could cause this.  Those that are valid, should be handled
3535                 // by remapping the exception callback.  Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;').
3536                 // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions).
3537                 ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr, debugString, options);
3538             }
3539             else
3540             {
3541                 ReportFailure<T>(__R_FN_CALL_FULL, hr, debugString, options);
3542             }
3543         }
3544 
3545         template<>
3546         inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported)
3547         {
3548             ReportFailure_CaughtExceptionCommonNoReturnBase<FailureType::FailFast>(__R_FN_CALL_FULL, debugString, debugStringChars, supported);
3549         }
3550 
3551         template<>
3552         inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported)
3553         {
3554             ReportFailure_CaughtExceptionCommonNoReturnBase<FailureType::Exception>(__R_FN_CALL_FULL, debugString, debugStringChars, supported);
3555         }
3556 
3557         template<FailureType T>
3558         inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3559         {
3560             wchar_t message[2048];
3561             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3562             ReportFailure<T>(__R_FN_CALL_FULL, hr, message);
3563         }
3564 
3565         template<>
3566         inline RESULT_NORETURN void ReportFailure_Msg<FailureType::FailFast>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3567         {
3568             wchar_t message[2048];
3569             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3570             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr, message);
3571         }
3572 
3573         template<>
3574         inline RESULT_NORETURN void ReportFailure_Msg<FailureType::Exception>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3575         {
3576             wchar_t message[2048];
3577             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3578             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr, message);
3579         }
3580 
3581         template <FailureType T>
3582         inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...)
3583         {
3584             va_list argList;
3585             va_start(argList, formatString);
3586             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3587         }
3588 
3589         template<FailureType T>
3590         __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr)
3591         {
3592             ReportFailure<T>(__R_FN_CALL_FULL, hr);
3593         }
3594 
3595         template<>
3596         __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr<FailureType::FailFast>(__R_FN_PARAMS_FULL, HRESULT hr)
3597         {
3598             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3599         }
3600 
3601         template<>
3602         __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr<FailureType::Exception>(__R_FN_PARAMS_FULL, HRESULT hr)
3603         {
3604             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3605         }
3606 
3607         __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr)
3608         {
3609             switch(type)
3610             {
3611             case FailureType::Exception:
3612                 ReportFailure_Hr<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3613                 break;
3614             case FailureType::FailFast:
3615                 ReportFailure_Hr<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3616                 break;
3617             case FailureType::Log:
3618                 ReportFailure_Hr<FailureType::Log>(__R_FN_CALL_FULL, hr);
3619                 break;
3620             case FailureType::Return:
3621                 ReportFailure_Hr<FailureType::Return>(__R_FN_CALL_FULL, hr);
3622                 break;
3623             }
3624         }
3625 
3626         template<FailureType T>
3627         _Success_(true)
3628         _Translates_Win32_to_HRESULT_(err)
3629         __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err)
3630         {
3631             const auto hr = __HRESULT_FROM_WIN32(err);
3632             ReportFailure<T>(__R_FN_CALL_FULL, hr);
3633             return hr;
3634         }
3635 
3636         template<>
3637         _Success_(true)
3638         _Translates_Win32_to_HRESULT_(err)
3639         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32<FailureType::FailFast>(__R_FN_PARAMS_FULL, DWORD err)
3640         {
3641             const auto hr = __HRESULT_FROM_WIN32(err);
3642             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3643         }
3644 
3645         template<>
3646         _Success_(true)
3647         _Translates_Win32_to_HRESULT_(err)
3648         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32<FailureType::Exception>(__R_FN_PARAMS_FULL, DWORD err)
3649         {
3650             const auto hr = __HRESULT_FROM_WIN32(err);
3651             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3652         }
3653 
3654         template<FailureType T>
3655         __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL)
3656         {
3657             const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3658             const auto hr = __HRESULT_FROM_WIN32(err);
3659             ReportFailure<T>(__R_FN_CALL_FULL, hr);
3660             return err;
3661         }
3662 
3663         template<>
3664         __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError<FailureType::FailFast>(__R_FN_PARAMS_FULL)
3665         {
3666             const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3667             const auto hr = __HRESULT_FROM_WIN32(err);
3668             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3669         }
3670 
3671         template<>
3672         __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError<FailureType::Exception>(__R_FN_PARAMS_FULL)
3673         {
3674             const auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3675             const auto hr = __HRESULT_FROM_WIN32(err);
3676             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3677         }
3678 
3679         template<FailureType T>
3680         _Success_(true)
3681         _Translates_last_error_to_HRESULT_
3682         __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL)
3683         {
3684             const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3685             ReportFailure<T>(__R_FN_CALL_FULL, hr);
3686             return hr;
3687         }
3688 
3689         template<>
3690         _Success_(true)
3691         _Translates_last_error_to_HRESULT_
3692         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr<FailureType::FailFast>(__R_FN_PARAMS_FULL)
3693         {
3694             const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3695             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3696         }
3697 
3698         template<>
3699         _Success_(true)
3700         _Translates_last_error_to_HRESULT_
3701         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr<FailureType::Exception>(__R_FN_PARAMS_FULL)
3702         {
3703             const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3704             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3705         }
3706 
3707         template<FailureType T>
3708         _Success_(true)
3709         _Translates_NTSTATUS_to_HRESULT_(status)
3710         __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status)
3711         {
3712             const auto hr = wil::details::NtStatusToHr(status);
3713             ReportFailure<T>(__R_FN_CALL_FULL, hr);
3714             return hr;
3715         }
3716 
3717         template<>
3718         _Success_(true)
3719         _Translates_NTSTATUS_to_HRESULT_(status)
3720         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus<FailureType::FailFast>(__R_FN_PARAMS_FULL, NTSTATUS status)
3721         {
3722             const auto hr = wil::details::NtStatusToHr(status);
3723             ReportFailure<FailureType::FailFast>(__R_FN_CALL_FULL, hr);
3724         }
3725 
3726         template<>
3727         _Success_(true)
3728         _Translates_NTSTATUS_to_HRESULT_(status)
3729         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus<FailureType::Exception>(__R_FN_PARAMS_FULL, NTSTATUS status)
3730         {
3731             const auto hr = wil::details::NtStatusToHr(status);
3732             ReportFailure<FailureType::Exception>(__R_FN_CALL_FULL, hr);
3733         }
3734 
3735         template<FailureType T>
3736         __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported)
3737         {
3738             wchar_t message[2048];
3739             message[0] = L'\0';
3740             return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported);
3741         }
3742 
3743         template<>
3744         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException<FailureType::FailFast>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
3745         {
3746             wchar_t message[2048];
3747             message[0] = L'\0';
3748             ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported);
3749         }
3750 
3751         template<>
3752         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException<FailureType::Exception>(__R_FN_PARAMS_FULL, SupportedExceptions supported)
3753         {
3754             wchar_t message[2048];
3755             message[0] = L'\0';
3756             ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported);
3757         }
3758 
3759         template<FailureType T>
3760         __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3761         {
3762             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3763         }
3764 
3765         template<>
3766         __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3767         {
3768             ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, hr, formatString, argList);
3769         }
3770 
3771         template<>
3772         __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
3773         {
3774             ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, hr, formatString, argList);
3775         }
3776 
3777         template<FailureType T>
3778         _Success_(true)
3779         _Translates_Win32_to_HRESULT_(err)
3780         __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
3781         {
3782             auto hr = __HRESULT_FROM_WIN32(err);
3783             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3784             return hr;
3785         }
3786 
3787         template<>
3788         _Success_(true)
3789         _Translates_Win32_to_HRESULT_(err)
3790         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg<FailureType::FailFast>(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
3791         {
3792             auto hr = __HRESULT_FROM_WIN32(err);
3793             ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, hr, formatString, argList);
3794         }
3795 
3796         template<>
3797         _Success_(true)
3798         _Translates_Win32_to_HRESULT_(err)
3799         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg<FailureType::Exception>(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
3800         {
3801             auto hr = __HRESULT_FROM_WIN32(err);
3802             ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, hr, formatString, argList);
3803         }
3804 
3805         template<FailureType T>
3806         __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3807         {
3808             auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3809             auto hr = __HRESULT_FROM_WIN32(err);
3810             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3811             return err;
3812         }
3813 
3814         template<>
3815         __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3816         {
3817             auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3818             auto hr = __HRESULT_FROM_WIN32(err);
3819             ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, hr, formatString, argList);
3820         }
3821 
3822         template<>
3823         __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3824         {
3825             auto err = GetLastErrorFail(__R_FN_CALL_FULL);
3826             auto hr = __HRESULT_FROM_WIN32(err);
3827             ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, hr, formatString, argList);
3828         }
3829 
3830         template<FailureType T>
3831         _Success_(true)
3832         _Translates_last_error_to_HRESULT_
3833         __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3834         {
3835             auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3836             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3837             return hr;
3838         }
3839 
3840         template<>
3841         _Success_(true)
3842         _Translates_last_error_to_HRESULT_
3843         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3844         {
3845             auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3846             ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, hr, formatString, argList);
3847         }
3848 
3849         template<>
3850         _Success_(true)
3851         _Translates_last_error_to_HRESULT_
3852         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3853         {
3854             auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL);
3855             ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, hr, formatString, argList);
3856         }
3857 
3858         template<FailureType T>
3859         _Success_(true)
3860         _Translates_NTSTATUS_to_HRESULT_(status)
3861         __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
3862         {
3863             auto hr = wil::details::NtStatusToHr(status);
3864             ReportFailure_Msg<T>(__R_FN_CALL_FULL, hr, formatString, argList);
3865             return hr;
3866         }
3867 
3868         template<>
3869         _Success_(true)
3870         _Translates_NTSTATUS_to_HRESULT_(status)
3871         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
3872         {
3873             auto hr = wil::details::NtStatusToHr(status);
3874             ReportFailure_Msg<FailureType::FailFast>(__R_FN_CALL_FULL, hr, formatString, argList);
3875         }
3876 
3877         template<>
3878         _Success_(true)
3879         _Translates_NTSTATUS_to_HRESULT_(status)
3880         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
3881         {
3882             auto hr = wil::details::NtStatusToHr(status);
3883             ReportFailure_Msg<FailureType::Exception>(__R_FN_CALL_FULL, hr, formatString, argList);
3884         }
3885 
3886         template<FailureType T>
3887         __declspec(noinline) inline HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3888         {
3889             // Pre-populate the buffer with our message, the exception message will be added to it...
3890             wchar_t message[2048];
3891             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3892             StringCchCatW(message, ARRAYSIZE(message), L" -- ");
3893             return ReportFailure_CaughtExceptionCommon<T>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default);
3894         }
3895 
3896         template<>
3897         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg<FailureType::FailFast>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3898         {
3899             // Pre-populate the buffer with our message, the exception message will be added to it...
3900             wchar_t message[2048];
3901             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3902             StringCchCatW(message, ARRAYSIZE(message), L" -- ");
3903             ReportFailure_CaughtExceptionCommon<FailureType::FailFast>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default);
3904         }
3905 
3906         template<>
3907         __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg<FailureType::Exception>(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList)
3908         {
3909             // Pre-populate the buffer with our message, the exception message will be added to it...
3910             wchar_t message[2048];
3911             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3912             StringCchCatW(message, ARRAYSIZE(message), L" -- ");
3913             ReportFailure_CaughtExceptionCommon<FailureType::Exception>(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default);
3914         }
3915 
3916 
3917         //*****************************************************************************
3918         // Support for throwing custom exception types
3919         //*****************************************************************************
3920 
3921 #ifdef WIL_ENABLE_EXCEPTIONS
3922         inline HRESULT GetErrorCode(_In_ ResultException &exception) WI_NOEXCEPT
3923         {
3924             return exception.GetErrorCode();
3925         }
3926 
3927         inline void SetFailureInfo(_In_ FailureInfo const &failure, _Inout_ ResultException &exception) WI_NOEXCEPT
3928         {
3929             return exception.SetFailureInfo(failure);
3930         }
3931 
3932 #ifdef __cplusplus_winrt
3933         inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT
3934         {
3935             return exception->HResult;
3936         }
3937 
3938         inline void SetFailureInfo(_In_ FailureInfo const &, _Inout_ Platform::Exception^ exception) WI_NOEXCEPT
3939         {
3940             // no-op -- once a PlatformException^ is created, we can't modify the message, but this function must
3941             // exist to distinguish this from ResultException
3942         }
3943 #endif
3944 
3945         template <typename T>
3946         __declspec(noreturn) inline void ReportFailure_CustomExceptionHelper(_Inout_ T &exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr)
3947         {
3948             // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'"
3949             // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h.
3950             // This compilation error indicates an attempt to throw an incompatible exception type.
3951             const HRESULT hr = GetErrorCode(exception);
3952 
3953             FailureInfo failure;
3954             wchar_t debugString[2048];
3955             char callContextString[1024];
3956 
3957             LogFailure(__R_FN_CALL_FULL, FailureType::Exception, hr, message, false,     // false = does not need debug string
3958                        debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure);
3959 
3960             // push the failure info context into the custom exception class
3961             SetFailureInfo(failure, exception);
3962 
3963             throw exception;
3964         }
3965 
3966         template <typename T>
3967         __declspec(noreturn, noinline) inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception)
3968         {
3969             __R_FN_LOCALS_RA;
3970             ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL);
3971         }
3972 
3973         template <typename T>
3974         __declspec(noreturn, noinline) inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...)
3975         {
3976             va_list argList;
3977             va_start(argList, formatString);
3978             wchar_t message[2048];
3979             PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList);
3980 
3981             __R_FN_LOCALS_RA;
3982             ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message);
3983         }
3984 #endif
3985 
3986         namespace __R_NS_NAME
3987         {
3988             //*****************************************************************************
3989             // Return Macros
3990             //*****************************************************************************
3991 
3992             __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
3993             {
3994                 __R_FN_LOCALS;
3995                 wil::details::ReportFailure_Hr<FailureType::Return>(__R_DIRECT_FN_CALL hr);
3996             }
3997 
3998             _Success_(true)
3999             _Translates_Win32_to_HRESULT_(err)
4000             __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
4001             {
4002                 __R_FN_LOCALS;
4003                 return wil::details::ReportFailure_Win32<FailureType::Return>(__R_DIRECT_FN_CALL err);
4004             }
4005 
4006             _Success_(true)
4007             _Translates_last_error_to_HRESULT_
4008             __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4009             {
4010                 __R_FN_LOCALS;
4011                 return wil::details::ReportFailure_GetLastErrorHr<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
4012             }
4013 
4014             _Success_(true)
4015             _Translates_NTSTATUS_to_HRESULT_(status)
4016             __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4017             {
4018                 __R_FN_LOCALS;
4019                 return wil::details::ReportFailure_NtStatus<FailureType::Return>(__R_DIRECT_FN_CALL status);
4020             }
4021 
4022 #ifdef WIL_ENABLE_EXCEPTIONS
4023             __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4024             {
4025                 __R_FN_LOCALS;
4026                 return wil::details::ReportFailure_CaughtException<FailureType::Return>(__R_DIRECT_FN_CALL_ONLY);
4027             }
4028 #endif
4029 
4030             __R_DIRECT_METHOD(void, Return_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4031             {
4032                 va_list argList;
4033                 va_start(argList, formatString);
4034                 __R_FN_LOCALS;
4035                 wil::details::ReportFailure_HrMsg<FailureType::Return>(__R_DIRECT_FN_CALL hr, formatString, argList);
4036             }
4037 
4038             _Success_(true)
4039             _Translates_Win32_to_HRESULT_(err)
4040             __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4041             {
4042                 va_list argList;
4043                 va_start(argList, formatString);
4044                 __R_FN_LOCALS;
4045                 return wil::details::ReportFailure_Win32Msg<FailureType::Return>(__R_DIRECT_FN_CALL err, formatString, argList);
4046             }
4047 
4048             _Success_(true)
4049             _Translates_last_error_to_HRESULT_
4050             __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4051             {
4052                 va_list argList;
4053                 va_start(argList, formatString);
4054                 __R_FN_LOCALS;
4055                 return wil::details::ReportFailure_GetLastErrorHrMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
4056             }
4057 
4058             _Success_(true)
4059             _Translates_NTSTATUS_to_HRESULT_(status)
4060             __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4061             {
4062                 va_list argList;
4063                 va_start(argList, formatString);
4064                 __R_FN_LOCALS;
4065                 return wil::details::ReportFailure_NtStatusMsg<FailureType::Return>(__R_DIRECT_FN_CALL status, formatString, argList);
4066             }
4067 
4068 #ifdef WIL_ENABLE_EXCEPTIONS
4069             __R_DIRECT_METHOD(HRESULT, Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4070             {
4071                 va_list argList;
4072                 va_start(argList, formatString);
4073                 __R_FN_LOCALS;
4074                 return wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Return>(__R_DIRECT_FN_CALL formatString, argList);
4075             }
4076 #endif
4077 
4078             //*****************************************************************************
4079             // Log Macros
4080             //*****************************************************************************
4081 
4082             _Post_satisfies_(return == hr)
4083             __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4084             {
4085                 __R_FN_LOCALS;
4086                 wil::details::ReportFailure_Hr<FailureType::Log>(__R_DIRECT_FN_CALL hr);
4087                 return hr;
4088             }
4089 
4090             _Post_satisfies_(return == err)
4091             __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
4092             {
4093                 __R_FN_LOCALS;
4094                 wil::details::ReportFailure_Win32<FailureType::Log>(__R_DIRECT_FN_CALL err);
4095                 return err;
4096             }
4097 
4098             __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4099             {
4100                 __R_FN_LOCALS;
4101                 return wil::details::ReportFailure_GetLastError<FailureType::Log>(__R_DIRECT_FN_CALL_ONLY);
4102             }
4103 
4104             _Post_satisfies_(return == status)
4105             __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4106             {
4107                 __R_FN_LOCALS;
4108                 wil::details::ReportFailure_NtStatus<FailureType::Log>(__R_DIRECT_FN_CALL status);
4109                 return status;
4110             }
4111 
4112 #ifdef WIL_ENABLE_EXCEPTIONS
4113             __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4114             {
4115                 __R_FN_LOCALS;
4116                 return wil::details::ReportFailure_CaughtException<FailureType::Log>(__R_DIRECT_FN_CALL_ONLY);
4117             }
4118 #endif
4119 
4120             __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4121             {
4122                 __R_FN_LOCALS;
4123                 wil::details::ReportFailure_Hr<FailureType::Log>(__R_INTERNAL_FN_CALL hr);
4124             }
4125 
4126             __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
4127             {
4128                 __R_FN_LOCALS;
4129                 wil::details::ReportFailure_GetLastError<FailureType::Log>(__R_INTERNAL_FN_CALL_ONLY);
4130             }
4131 
4132             __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
4133             {
4134                 __R_FN_LOCALS;
4135                 wil::details::ReportFailure_Win32<FailureType::Log>(__R_INTERNAL_FN_CALL err);
4136             }
4137 
4138             __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
4139             {
4140                 __R_FN_LOCALS;
4141                 wil::details::ReportFailure_Hr<FailureType::Log>(__R_INTERNAL_FN_CALL E_OUTOFMEMORY);
4142             }
4143 
4144             __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4145             {
4146                 __R_FN_LOCALS;
4147                 wil::details::ReportFailure_NtStatus<FailureType::Log>(__R_INTERNAL_FN_CALL status);
4148             }
4149 
4150             _Post_satisfies_(return == hr)
4151             __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4152             {
4153                 if (FAILED(hr))
4154                 {
4155                     __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4156                 }
4157                 return hr;
4158             }
4159 
4160             _Post_satisfies_(return == hr)
4161             __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, unsigned int expectedCount, ...) WI_NOEXCEPT
4162             {
4163                 va_list args;
4164                 va_start(args, expectedCount);
4165 
4166                 if (FAILED(hr))
4167                 {
4168                     unsigned int expectedIndex;
4169                     for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex)
4170                     {
4171                         if (hr == va_arg(args, HRESULT))
4172                         {
4173                             break;
4174                         }
4175                     }
4176 
4177                     if (expectedIndex == expectedCount)
4178                     {
4179                         __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4180                     }
4181                 }
4182 
4183                 va_end(args);
4184                 return hr;
4185             }
4186 
4187             _Post_satisfies_(return == ret)
4188             __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT
4189             {
4190                 if (!ret)
4191                 {
4192                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4193                 }
4194                 return ret;
4195             }
4196 
4197             _Post_satisfies_(return == err)
4198             __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT
4199             {
4200                 if (FAILED_WIN32(err))
4201                 {
4202                     __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err);
4203                 }
4204                 return err;
4205             }
4206 
4207             _Post_satisfies_(return == handle)
4208             __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
4209             {
4210                 if (handle == INVALID_HANDLE_VALUE)
4211                 {
4212                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4213                 }
4214                 return handle;
4215             }
4216 
4217             _Post_satisfies_(return == handle)
4218             __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
4219             {
4220                 if (handle == nullptr)
4221                 {
4222                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4223                 }
4224                 return handle;
4225             }
4226 
4227             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4228             _Post_satisfies_(return == pointer)
4229             __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4230             {
4231                 if (pointer == nullptr)
4232                 {
4233                     __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
4234                 }
4235                 return pointer;
4236             }
4237 
4238             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4239             __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT
4240             {
4241                 if (pointer == nullptr)
4242                 {
4243                     __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
4244                 }
4245             }
4246 
4247             _Post_satisfies_(return == condition)
4248             __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
4249             {
4250                 if (condition)
4251                 {
4252                     __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4253                 }
4254                 return condition;
4255             }
4256 
4257             _Post_satisfies_(return == condition)
4258             __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
4259             {
4260                 if (!condition)
4261                 {
4262                     __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4263                 }
4264                 return condition;
4265             }
4266 
4267             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4268             _Post_satisfies_(return == pointer)
4269             __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4270             {
4271                 if (pointer == nullptr)
4272                 {
4273                     __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4274                 }
4275                 return pointer;
4276             }
4277 
4278             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4279             __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT
4280             {
4281                 if (pointer == nullptr)
4282                 {
4283                     __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr);
4284                 }
4285             }
4286 
4287             _Post_satisfies_(return == condition)
4288             __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
4289             {
4290                 if (condition)
4291                 {
4292                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4293                 }
4294                 return condition;
4295             }
4296 
4297             _Post_satisfies_(return == condition)
4298             __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
4299             {
4300                 if (!condition)
4301                 {
4302                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4303                 }
4304                 return condition;
4305             }
4306 
4307             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4308             _Post_satisfies_(return == pointer)
4309             __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4310             {
4311                 if (pointer == nullptr)
4312                 {
4313                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4314                 }
4315                 return pointer;
4316             }
4317 
4318             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4319             __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT
4320             {
4321                 if (pointer == nullptr)
4322                 {
4323                     __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
4324                 }
4325             }
4326 
4327             _Post_satisfies_(return == status)
4328             __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4329             {
4330                 if (FAILED_NTSTATUS(status))
4331                 {
4332                     __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status);
4333                 }
4334                 return status;
4335             }
4336 
4337             _Post_satisfies_(return == hr)
4338             __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4339             {
4340                 va_list argList;
4341                 va_start(argList, formatString);
4342                 __R_FN_LOCALS;
4343                 wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_DIRECT_FN_CALL hr, formatString, argList);
4344                 return hr;
4345             }
4346 
4347             _Post_satisfies_(return == err)
4348             __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4349             {
4350                 va_list argList;
4351                 va_start(argList, formatString);
4352                 __R_FN_LOCALS;
4353                 wil::details::ReportFailure_Win32Msg<FailureType::Log>(__R_DIRECT_FN_CALL err, formatString, argList);
4354                 return err;
4355             }
4356 
4357             __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4358             {
4359                 va_list argList;
4360                 va_start(argList, formatString);
4361                 __R_FN_LOCALS;
4362                 return wil::details::ReportFailure_GetLastErrorMsg<FailureType::Log>(__R_DIRECT_FN_CALL formatString, argList);
4363             }
4364 
4365             _Post_satisfies_(return == status)
4366             __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4367             {
4368                 va_list argList;
4369                 va_start(argList, formatString);
4370                 __R_FN_LOCALS;
4371                 wil::details::ReportFailure_NtStatusMsg<FailureType::Log>(__R_DIRECT_FN_CALL status, formatString, argList);
4372                 return status;
4373             }
4374 
4375 #ifdef WIL_ENABLE_EXCEPTIONS
4376             __R_DIRECT_METHOD(HRESULT, Log_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4377             {
4378                 va_list argList;
4379                 va_start(argList, formatString);
4380                 __R_FN_LOCALS;
4381                 return wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Log>(__R_DIRECT_FN_CALL formatString, argList);
4382             }
4383 #endif
4384 
4385             __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4386             {
4387                 __R_FN_LOCALS;
4388                 wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
4389             }
4390 
4391             __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4392             {
4393                 __R_FN_LOCALS;
4394                 wil::details::ReportFailure_GetLastErrorMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList);
4395             }
4396 
4397             __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4398             {
4399                 __R_FN_LOCALS;
4400                 wil::details::ReportFailure_Win32Msg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
4401             }
4402 
4403             __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4404             {
4405                 __R_FN_LOCALS;
4406                 wil::details::ReportFailure_HrMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
4407             }
4408 
4409             __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4410             {
4411                 __R_FN_LOCALS;
4412                 wil::details::ReportFailure_NtStatusMsg<FailureType::Log>(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
4413             }
4414 
4415             _Post_satisfies_(return == hr)
4416             __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4417             {
4418                 if (FAILED(hr))
4419                 {
4420                     va_list argList;
4421                     va_start(argList, formatString);
4422                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4423                 }
4424                 return hr;
4425             }
4426 
4427             _Post_satisfies_(return == ret)
4428             __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4429             {
4430                 if (!ret)
4431                 {
4432                     va_list argList;
4433                     va_start(argList, formatString);
4434                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4435                 }
4436                 return ret;
4437             }
4438 
4439             _Post_satisfies_(return == err)
4440             __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4441             {
4442                 if (FAILED_WIN32(err))
4443                 {
4444                     va_list argList;
4445                     va_start(argList, formatString);
4446                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
4447                 }
4448                 return err;
4449             }
4450 
4451             _Post_satisfies_(return == handle)
4452             __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4453             {
4454                 if (handle == INVALID_HANDLE_VALUE)
4455                 {
4456                     va_list argList;
4457                     va_start(argList, formatString);
4458                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4459                 }
4460                 return handle;
4461             }
4462 
4463             _Post_satisfies_(return == handle)
4464             __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4465             {
4466                 if (handle == nullptr)
4467                 {
4468                     va_list argList;
4469                     va_start(argList, formatString);
4470                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4471                 }
4472                 return handle;
4473             }
4474 
4475             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4476             _Post_satisfies_(return == pointer)
4477             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4478             {
4479                 if (pointer == nullptr)
4480                 {
4481                     va_list argList;
4482                     va_start(argList, formatString);
4483                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
4484                 }
4485                 return pointer;
4486             }
4487 
4488             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4489             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4490             {
4491                 if (pointer == nullptr)
4492                 {
4493                     va_list argList;
4494                     va_start(argList, formatString);
4495                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
4496                 }
4497             }
4498 
4499             _Post_satisfies_(return == condition)
4500             __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4501             {
4502                 if (condition)
4503                 {
4504                     va_list argList;
4505                     va_start(argList, formatString);
4506                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4507                 }
4508                 return condition;
4509             }
4510 
4511             _Post_satisfies_(return == condition)
4512             __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4513             {
4514                 if (!condition)
4515                 {
4516                     va_list argList;
4517                     va_start(argList, formatString);
4518                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4519                 }
4520                 return condition;
4521             }
4522 
4523             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4524             _Post_satisfies_(return == pointer)
4525             __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
4526             {
4527                 if (pointer == nullptr)
4528                 {
4529                     va_list argList;
4530                     va_start(argList, formatString);
4531                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4532                 }
4533                 return pointer;
4534             }
4535 
4536             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4537             __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
4538             {
4539                 if (pointer == nullptr)
4540                 {
4541                     va_list argList;
4542                     va_start(argList, formatString);
4543                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4544                 }
4545             }
4546 
4547             _Post_satisfies_(return == condition)
4548             __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4549             {
4550                 if (condition)
4551                 {
4552                     va_list argList;
4553                     va_start(argList, formatString);
4554                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4555                 }
4556                 return condition;
4557             }
4558 
4559             _Post_satisfies_(return == condition)
4560             __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4561             {
4562                 if (!condition)
4563                 {
4564                     va_list argList;
4565                     va_start(argList, formatString);
4566                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4567                 }
4568                 return condition;
4569             }
4570 
4571             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4572             _Post_satisfies_(return == pointer)
4573             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4574             {
4575                 if (pointer == nullptr)
4576                 {
4577                     va_list argList;
4578                     va_start(argList, formatString);
4579                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4580                 }
4581                 return pointer;
4582             }
4583 
4584             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4585             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4586             {
4587                 if (pointer == nullptr)
4588                 {
4589                     va_list argList;
4590                     va_start(argList, formatString);
4591                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4592                 }
4593             }
4594 
4595             _Post_satisfies_(return == status)
4596             __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4597             {
4598                 if (FAILED_NTSTATUS(status))
4599                 {
4600                     va_list argList;
4601                     va_start(argList, formatString);
4602                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
4603                 }
4604                 return status;
4605             }
4606         } // namespace __R_NS_NAME
4607 
4608         namespace __RFF_NS_NAME
4609         {
4610             //*****************************************************************************
4611             // FailFast Macros
4612             //*****************************************************************************
4613 
4614             __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4615             {
4616                 __RFF_FN_LOCALS;
4617                 wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_DIRECT_FN_CALL hr);
4618             }
4619 
4620             __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT
4621             {
4622                 __RFF_FN_LOCALS;
4623                 wil::details::ReportFailure_Win32<FailureType::FailFast>(__RFF_DIRECT_FN_CALL err);
4624             }
4625 
4626             __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4627             {
4628                 __RFF_FN_LOCALS;
4629                 wil::details::ReportFailure_GetLastError<FailureType::FailFast>(__RFF_DIRECT_FN_CALL_ONLY);
4630             }
4631 
4632             __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4633             {
4634                 __RFF_FN_LOCALS;
4635                 wil::details::ReportFailure_NtStatus<FailureType::FailFast>(__RFF_DIRECT_FN_CALL status);
4636             }
4637 
4638 #ifdef WIL_ENABLE_EXCEPTIONS
4639             __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
4640             {
4641                 __RFF_FN_LOCALS;
4642                 wil::details::ReportFailure_CaughtException<FailureType::FailFast>(__RFF_DIRECT_FN_CALL_ONLY);
4643             }
4644 #endif
4645 
4646             __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4647             {
4648                 __RFF_FN_LOCALS;
4649                 wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL hr);
4650             }
4651 
4652             __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
4653             {
4654                 __RFF_FN_LOCALS;
4655                 wil::details::ReportFailure_GetLastError<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL_ONLY);
4656             }
4657 
4658             __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT
4659             {
4660                 __RFF_FN_LOCALS;
4661                 wil::details::ReportFailure_Win32<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL err);
4662             }
4663 
4664             __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
4665             {
4666                 __RFF_FN_LOCALS;
4667                 wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY);
4668             }
4669 
4670             __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4671             {
4672                 __RFF_FN_LOCALS;
4673                 wil::details::ReportFailure_NtStatus<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL status);
4674             }
4675 
4676             _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
4677             __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT
4678             {
4679                 if (FAILED(hr))
4680                 {
4681                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
4682                 }
4683                 return hr;
4684             }
4685 
4686             _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
4687             __RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT
4688             {
4689                 if (!ret)
4690                 {
4691                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4692                 }
4693                 return ret;
4694             }
4695 
4696             _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
4697             __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) WI_NOEXCEPT
4698             {
4699                 if (FAILED_WIN32(err))
4700                 {
4701                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err);
4702                 }
4703                 return err;
4704             }
4705 
4706             _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
4707             __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
4708             {
4709                 if (handle == INVALID_HANDLE_VALUE)
4710                 {
4711                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4712                 }
4713                 return handle;
4714             }
4715 
4716             _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
4717             __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT
4718             {
4719                 if (handle == nullptr)
4720                 {
4721                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4722                 }
4723                 return handle;
4724             }
4725 
4726             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4727             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
4728             __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4729             {
4730                 if (pointer == nullptr)
4731                 {
4732                     __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4733                 }
4734                 return pointer;
4735             }
4736 
4737             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4738             __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT
4739             {
4740                 if (pointer == nullptr)
4741                 {
4742                     __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4743                 }
4744             }
4745 
4746             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
4747             __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
4748             {
4749                 if (condition)
4750                 {
4751                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
4752                 }
4753                 return condition;
4754             }
4755 
4756             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
4757             __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT
4758             {
4759                 if (!condition)
4760                 {
4761                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
4762                 }
4763                 return condition;
4764             }
4765 
4766             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4767             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
4768             __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4769             {
4770                 if (pointer == nullptr)
4771                 {
4772                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
4773                 }
4774                 return pointer;
4775             }
4776 
4777             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4778             __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT
4779             {
4780                 if (pointer == nullptr)
4781                 {
4782                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr);
4783                 }
4784             }
4785 
4786             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
4787             __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
4788             {
4789                 if (condition)
4790                 {
4791                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4792                 }
4793                 return condition;
4794             }
4795 
4796             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
4797             __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
4798             {
4799                 if (!condition)
4800                 {
4801                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4802                 }
4803                 return condition;
4804             }
4805 
4806             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4807             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
4808             __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
4809             {
4810                 if (pointer == nullptr)
4811                 {
4812                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4813                 }
4814                 return pointer;
4815             }
4816 
4817             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4818             __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT
4819             {
4820                 if (pointer == nullptr)
4821                 {
4822                     __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY);
4823                 }
4824             }
4825 
4826             _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
4827             __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT
4828             {
4829                 if (FAILED_NTSTATUS(status))
4830                 {
4831                     __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status);
4832                 }
4833                 return status;
4834             }
4835 
4836             __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4837             {
4838                 va_list argList;
4839                 va_start(argList, formatString);
4840                 __RFF_FN_LOCALS;
4841                 wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL hr, formatString, argList);
4842             }
4843 
4844             __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4845             {
4846                 va_list argList;
4847                 va_start(argList, formatString);
4848                 __RFF_FN_LOCALS;
4849                 wil::details::ReportFailure_Win32Msg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL err, formatString, argList);
4850             }
4851 
4852             __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4853             {
4854                 va_list argList;
4855                 va_start(argList, formatString);
4856                 __RFF_FN_LOCALS;
4857                 wil::details::ReportFailure_GetLastErrorMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL formatString, argList);
4858             }
4859 
4860             __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4861             {
4862                 va_list argList;
4863                 va_start(argList, formatString);
4864                 __RFF_FN_LOCALS;
4865                 wil::details::ReportFailure_NtStatusMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL status, formatString, argList);
4866             }
4867 
4868 #ifdef WIL_ENABLE_EXCEPTIONS
4869             __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4870             {
4871                 va_list argList;
4872                 va_start(argList, formatString);
4873                 __RFF_FN_LOCALS;
4874                 wil::details::ReportFailure_CaughtExceptionMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL formatString, argList);
4875             }
4876 #endif
4877 
4878             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4879             {
4880                 __RFF_FN_LOCALS;
4881                 wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
4882             }
4883 
4884             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4885             {
4886                 __RFF_FN_LOCALS;
4887                 wil::details::ReportFailure_GetLastErrorMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList);
4888             }
4889 
4890             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4891             {
4892                 __RFF_FN_LOCALS;
4893                 wil::details::ReportFailure_Win32Msg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
4894             }
4895 
4896             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4897             {
4898                 __RFF_FN_LOCALS;
4899                 wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
4900             }
4901 
4902             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
4903             {
4904                 __RFF_FN_LOCALS;
4905                 wil::details::ReportFailure_NtStatusMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
4906             }
4907 
4908             _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
4909             __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4910             {
4911                 if (FAILED(hr))
4912                 {
4913                     va_list argList;
4914                     va_start(argList, formatString);
4915                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
4916                 }
4917                 return hr;
4918             }
4919 
4920             _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
4921             __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4922             {
4923                 if (!ret)
4924                 {
4925                     va_list argList;
4926                     va_start(argList, formatString);
4927                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4928                 }
4929                 return ret;
4930             }
4931 
4932             _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
4933             __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg)(__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4934             {
4935                 if (FAILED_WIN32(err))
4936                 {
4937                     va_list argList;
4938                     va_start(argList, formatString);
4939                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
4940                 }
4941                 return err;
4942             }
4943 
4944             _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
4945             __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4946             {
4947                 if (handle == INVALID_HANDLE_VALUE)
4948                 {
4949                     va_list argList;
4950                     va_start(argList, formatString);
4951                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4952                 }
4953                 return handle;
4954             }
4955 
4956             _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
4957             __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4958             {
4959                 if (handle == nullptr)
4960                 {
4961                     va_list argList;
4962                     va_start(argList, formatString);
4963                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
4964                 }
4965                 return handle;
4966             }
4967 
4968             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
4969             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
4970             __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
4971             {
4972                 if (pointer == nullptr)
4973                 {
4974                     va_list argList;
4975                     va_start(argList, formatString);
4976                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
4977                 }
4978                 return pointer;
4979             }
4980 
4981             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
4982             __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4983             {
4984                 if (pointer == nullptr)
4985                 {
4986                     va_list argList;
4987                     va_start(argList, formatString);
4988                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
4989                 }
4990             }
4991 
4992             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
4993             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
4994             {
4995                 if (condition)
4996                 {
4997                     va_list argList;
4998                     va_start(argList, formatString);
4999                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5000                 }
5001                 return condition;
5002             }
5003 
5004             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5005             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5006             {
5007                 if (!condition)
5008                 {
5009                     va_list argList;
5010                     va_start(argList, formatString);
5011                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5012                 }
5013                 return condition;
5014             }
5015 
5016             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5017             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5018             __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
5019             {
5020                 if (pointer == nullptr)
5021                 {
5022                     va_list argList;
5023                     va_start(argList, formatString);
5024                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5025                 }
5026                 return pointer;
5027             }
5028 
5029             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5030             __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
5031             {
5032                 if (pointer == nullptr)
5033                 {
5034                     va_list argList;
5035                     va_start(argList, formatString);
5036                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5037                 }
5038             }
5039 
5040             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5041             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5042             {
5043                 if (condition)
5044                 {
5045                     va_list argList;
5046                     va_start(argList, formatString);
5047                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5048                 }
5049                 return condition;
5050             }
5051 
5052             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5053             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5054             {
5055                 if (!condition)
5056                 {
5057                     va_list argList;
5058                     va_start(argList, formatString);
5059                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5060                 }
5061                 return condition;
5062             }
5063 
5064             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5065             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5066             __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
5067             {
5068                 if (pointer == nullptr)
5069                 {
5070                     va_list argList;
5071                     va_start(argList, formatString);
5072                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5073                 }
5074                 return pointer;
5075             }
5076 
5077             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5078             __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5079             {
5080                 if (pointer == nullptr)
5081                 {
5082                     va_list argList;
5083                     va_start(argList, formatString);
5084                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5085                 }
5086             }
5087 
5088             _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
5089             __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5090             {
5091                 if (FAILED_NTSTATUS(status))
5092                 {
5093                     va_list argList;
5094                     va_start(argList, formatString);
5095                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
5096                 }
5097                 return status;
5098             }
5099 
5100             __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT
5101             {
5102                 __RFF_FN_LOCALS;
5103                 wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_DIRECT_FN_CALL E_UNEXPECTED);
5104             }
5105 
5106             __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT
5107             {
5108                 __RFF_FN_LOCALS;
5109                 wil::details::ReportFailure_Hr<FailureType::FailFast>(__RFF_INTERNAL_FN_CALL E_UNEXPECTED);
5110             }
5111 
5112             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5113             __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
5114             {
5115                 if (condition)
5116                 {
5117                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
5118                 }
5119                 return condition;
5120             }
5121 
5122             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5123             __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT
5124             {
5125                 if (!condition)
5126                 {
5127                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
5128                 }
5129                 return condition;
5130             }
5131 
5132             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5133             __WI_SUPPRESS_NULLPTR_ANALYSIS
5134             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5135             __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
5136             {
5137                 if (pointer == nullptr)
5138                 {
5139                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
5140                 }
5141                 return pointer;
5142             }
5143 
5144             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5145             __WI_SUPPRESS_NULLPTR_ANALYSIS
5146             __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT
5147             {
5148                 if (pointer == nullptr)
5149                 {
5150                     __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY);
5151                 }
5152             }
5153 
5154             __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5155             {
5156                 va_list argList;
5157                 va_start(argList, formatString);
5158                 __RFF_FN_LOCALS;
5159                 wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_DIRECT_FN_CALL E_UNEXPECTED, formatString, argList);
5160             }
5161 
5162             __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT
5163             {
5164                 __RFF_FN_LOCALS;
5165                 wil::details::ReportFailure_HrMsg<FailureType::FailFast>(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, formatString, argList);
5166             }
5167 
5168             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5169             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5170             {
5171                 if (condition)
5172                 {
5173                     va_list argList;
5174                     va_start(argList, formatString);
5175                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5176                 }
5177                 return condition;
5178             }
5179 
5180             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5181             __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5182             {
5183                 if (!condition)
5184                 {
5185                     va_list argList;
5186                     va_start(argList, formatString);
5187                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5188                 }
5189                 return condition;
5190             }
5191 
5192             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5193             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5194             __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
5195             {
5196                 if (pointer == nullptr)
5197                 {
5198                     va_list argList;
5199                     va_start(argList, formatString);
5200                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5201                 }
5202                 return pointer;
5203             }
5204 
5205             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5206             __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT
5207             {
5208                 if (pointer == nullptr)
5209                 {
5210                     va_list argList;
5211                     va_start(argList, formatString);
5212                     __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5213                 }
5214             }
5215 
5216             //*****************************************************************************
5217             // FailFast Immediate Macros
5218             //*****************************************************************************
5219 
5220             __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT
5221             {
5222                 __fastfail(FAST_FAIL_FATAL_APP_EXIT);
5223             }
5224 
5225             __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT
5226             {
5227                 __fastfail(FAST_FAIL_FATAL_APP_EXIT);
5228             }
5229 
5230             _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
5231             __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT
5232             {
5233                 if (FAILED(hr))
5234                 {
5235                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5236                 }
5237                 return hr;
5238             }
5239 
5240             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5241             __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT
5242             {
5243                 if (condition)
5244                 {
5245                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5246                 }
5247                 return condition;
5248             }
5249 
5250             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5251             __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT
5252             {
5253                 if (!condition)
5254                 {
5255                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5256                 }
5257                 return condition;
5258             }
5259 
5260             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5261             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5262             __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull)(_Pre_maybenull_ PointerT pointer) WI_NOEXCEPT
5263             {
5264                 if (pointer == nullptr)
5265                 {
5266                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5267                 }
5268                 return pointer;
5269             }
5270 
5271             template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5272             __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)(_In_opt_ const PointerT& pointer) WI_NOEXCEPT
5273             {
5274                 if (pointer == nullptr)
5275                 {
5276                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5277                 }
5278             }
5279 
5280             _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
5281             __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT
5282             {
5283                 if (FAILED_NTSTATUS(status))
5284                 {
5285                     __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)();
5286                 }
5287                 return status;
5288             }
5289         } // namespace __RFF_NS_NAME
5290 
5291         namespace __R_NS_NAME
5292         {
5293             //*****************************************************************************
5294             // Exception Macros
5295             //*****************************************************************************
5296 
5297 #ifdef WIL_ENABLE_EXCEPTIONS
5298             __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr)
5299             {
5300                 __R_FN_LOCALS;
5301                 wil::details::ReportFailure_Hr<FailureType::Exception>(__R_DIRECT_FN_CALL hr);
5302             }
5303 
5304             __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err)
5305             {
5306                 __R_FN_LOCALS;
5307                 wil::details::ReportFailure_Win32<FailureType::Exception>(__R_DIRECT_FN_CALL err);
5308             }
5309 
5310             __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY)
5311             {
5312                 __R_FN_LOCALS;
5313                 wil::details::ReportFailure_GetLastError<FailureType::Exception>(__R_DIRECT_FN_CALL_ONLY);
5314             }
5315 
5316             __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status)
5317             {
5318                 __R_FN_LOCALS;
5319                 wil::details::ReportFailure_NtStatus<FailureType::Exception>(__R_DIRECT_FN_CALL status);
5320             }
5321 
5322             __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY)
5323             {
5324                 __R_FN_LOCALS;
5325                 wil::details::ReportFailure_CaughtException<FailureType::Exception>(__R_DIRECT_FN_CALL_ONLY);
5326             }
5327 
5328             __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr)
5329             {
5330                 __R_FN_LOCALS;
5331                 wil::details::ReportFailure_Hr<FailureType::Exception>(__R_INTERNAL_FN_CALL hr);
5332             }
5333 
5334             __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY)
5335             {
5336                 __R_FN_LOCALS;
5337                 wil::details::ReportFailure_GetLastError<FailureType::Exception>(__R_INTERNAL_FN_CALL_ONLY);
5338             }
5339 
5340             __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err)
5341             {
5342                 __R_FN_LOCALS;
5343                 wil::details::ReportFailure_Win32<FailureType::Exception>(__R_INTERNAL_FN_CALL err);
5344             }
5345 
5346             __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY)
5347             {
5348                 __R_FN_LOCALS;
5349                 wil::details::ReportFailure_Hr<FailureType::Exception>(__R_INTERNAL_FN_CALL E_OUTOFMEMORY);
5350             }
5351 
5352             __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status)
5353             {
5354                 __R_FN_LOCALS;
5355                 wil::details::ReportFailure_NtStatus<FailureType::Exception>(__R_INTERNAL_FN_CALL status);
5356             }
5357 
5358             _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
5359             __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr)
5360             {
5361                 if (FAILED(hr))
5362                 {
5363                     __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
5364                 }
5365                 return hr;
5366             }
5367 
5368             _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
5369             __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret)
5370             {
5371                 if (!ret)
5372                 {
5373                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5374                 }
5375                 return ret;
5376             }
5377 
5378             _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
5379             __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err)
5380             {
5381                 if (FAILED_WIN32(err))
5382                 {
5383                     __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err);
5384                 }
5385                 return err;
5386             }
5387 
5388             _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
5389             __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
5390             {
5391                 if (handle == INVALID_HANDLE_VALUE)
5392                 {
5393                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5394                 }
5395                 return handle;
5396             }
5397 
5398             _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_)
5399             __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle)
5400             {
5401                 if (handle == nullptr)
5402                 {
5403                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5404                 }
5405                 return handle;
5406             }
5407 
5408             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5409             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5410             __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
5411             {
5412                 if (pointer == nullptr)
5413                 {
5414                     __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
5415                 }
5416                 return pointer;
5417             }
5418 
5419             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5420             __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer)
5421             {
5422                 if (pointer == nullptr)
5423                 {
5424                     __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY);
5425                 }
5426             }
5427 
5428             _Post_satisfies_(return == condition)
5429             _When_(condition, _Analysis_noreturn_)
5430             __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
5431             {
5432                 if (condition)
5433                 {
5434                     __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
5435                 }
5436                 return condition;
5437             }
5438 
5439             _Post_satisfies_(return == condition)
5440             _When_(!condition, _Analysis_noreturn_)
5441             __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition)
5442             {
5443                 if (!condition)
5444                 {
5445                     __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
5446                 }
5447                 return condition;
5448             }
5449 
5450             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5451             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5452             __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer)
5453             {
5454                 if (pointer == nullptr)
5455                 {
5456                     __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
5457                 }
5458                 return pointer;
5459             }
5460 
5461             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5462             __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer)
5463             {
5464                 if (pointer == nullptr)
5465                 {
5466                     __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr);
5467                 }
5468             }
5469 
5470             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5471             __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition)
5472             {
5473                 if (condition)
5474                 {
5475                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5476                 }
5477                 return condition;
5478             }
5479 
5480             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5481             __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition)
5482             {
5483                 if (!condition)
5484                 {
5485                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5486                 }
5487                 return condition;
5488             }
5489 
5490             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5491             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5492             __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer)
5493             {
5494                 if (pointer == nullptr)
5495                 {
5496                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5497                 }
5498                 return pointer;
5499             }
5500 
5501             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5502             __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer)
5503             {
5504                 if (pointer == nullptr)
5505                 {
5506                     __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY);
5507                 }
5508             }
5509 
5510             _Post_satisfies_(return == status)
5511             _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
5512             __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status)
5513             {
5514                 if (FAILED_NTSTATUS(status))
5515                 {
5516                     __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status);
5517                 }
5518                 return status;
5519             }
5520 
5521             __R_DIRECT_NORET_METHOD(void, Throw_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...)
5522             {
5523                 va_list argList;
5524                 va_start(argList, formatString);
5525                 __R_FN_LOCALS;
5526                 wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_DIRECT_FN_CALL hr, formatString, argList);
5527             }
5528 
5529             __R_DIRECT_NORET_METHOD(void, Throw_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...)
5530             {
5531                 va_list argList;
5532                 va_start(argList, formatString);
5533                 __R_FN_LOCALS;
5534                 wil::details::ReportFailure_Win32Msg<FailureType::Exception>(__R_DIRECT_FN_CALL err, formatString, argList);
5535             }
5536 
5537             __R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...)
5538             {
5539                 va_list argList;
5540                 va_start(argList, formatString);
5541                 __R_FN_LOCALS;
5542                 wil::details::ReportFailure_GetLastErrorMsg<FailureType::Exception>(__R_DIRECT_FN_CALL formatString, argList);
5543             }
5544 
5545             __R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...)
5546             {
5547                 va_list argList;
5548                 va_start(argList, formatString);
5549                 __R_FN_LOCALS;
5550                 wil::details::ReportFailure_NtStatusMsg<FailureType::Exception>(__R_DIRECT_FN_CALL status, formatString, argList);
5551             }
5552 
5553             __R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...)
5554             {
5555                 va_list argList;
5556                 va_start(argList, formatString);
5557                 __R_FN_LOCALS;
5558                 wil::details::ReportFailure_CaughtExceptionMsg<FailureType::Exception>(__R_DIRECT_FN_CALL formatString, argList);
5559             }
5560 
5561             __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList)
5562             {
5563                 __R_FN_LOCALS;
5564                 wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList);
5565             }
5566 
5567             __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList)
5568             {
5569                 __R_FN_LOCALS;
5570                 wil::details::ReportFailure_GetLastErrorMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList);
5571             }
5572 
5573             __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList)
5574             {
5575                 __R_FN_LOCALS;
5576                 wil::details::ReportFailure_Win32Msg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList);
5577             }
5578 
5579             __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList)
5580             {
5581                 __R_FN_LOCALS;
5582                 wil::details::ReportFailure_HrMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList);
5583             }
5584 
5585             __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList)
5586             {
5587                 __R_FN_LOCALS;
5588                 wil::details::ReportFailure_NtStatusMsg<FailureType::Exception>(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList);
5589             }
5590 
5591             _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_)
5592             __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...)
5593             {
5594                 if (FAILED(hr))
5595                 {
5596                     va_list argList;
5597                     va_start(argList, formatString);
5598                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5599                 }
5600                 return hr;
5601             }
5602 
5603             _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_)
5604             __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...)
5605             {
5606                 if (!ret)
5607                 {
5608                     va_list argList;
5609                     va_start(argList, formatString);
5610                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5611                 }
5612                 return ret;
5613             }
5614 
5615             _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_)
5616             __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...)
5617             {
5618                 if (FAILED_WIN32(err))
5619                 {
5620                     va_list argList;
5621                     va_start(argList, formatString);
5622                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList);
5623                 }
5624                 return err;
5625             }
5626 
5627             _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_)
5628             __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...)
5629             {
5630                 if (handle == INVALID_HANDLE_VALUE)
5631                 {
5632                     va_list argList;
5633                     va_start(argList, formatString);
5634                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5635                 }
5636                 return handle;
5637             }
5638 
5639             _Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_)
5640             __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...)
5641             {
5642                 if (handle == nullptr)
5643                 {
5644                     va_list argList;
5645                     va_start(argList, formatString);
5646                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5647                 }
5648                 return handle;
5649             }
5650 
5651             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5652             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5653             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...)
5654             {
5655                 if (pointer == nullptr)
5656                 {
5657                     va_list argList;
5658                     va_start(argList, formatString);
5659                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
5660                 }
5661                 return pointer;
5662             }
5663 
5664             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5665             __WI_SUPPRESS_NULLPTR_ANALYSIS
5666             _When_(pointer == nullptr, _Analysis_noreturn_)
5667             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
5668             {
5669                 if (pointer == nullptr)
5670                 {
5671                     va_list argList;
5672                     va_start(argList, formatString);
5673                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList);
5674                 }
5675             }
5676 
5677             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5678             __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...)
5679             {
5680                 if (condition)
5681                 {
5682                     va_list argList;
5683                     va_start(argList, formatString);
5684                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5685                 }
5686                 return condition;
5687             }
5688 
5689             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5690             __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...)
5691             {
5692                 if (!condition)
5693                 {
5694                     va_list argList;
5695                     va_start(argList, formatString);
5696                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5697                 }
5698                 return condition;
5699             }
5700 
5701             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5702             __WI_SUPPRESS_NULLPTR_ANALYSIS
5703             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5704             __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, ...)
5705             {
5706                 if (pointer == nullptr)
5707                 {
5708                     va_list argList;
5709                     va_start(argList, formatString);
5710                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5711                 }
5712                 return pointer;
5713             }
5714 
5715             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5716             __WI_SUPPRESS_NULLPTR_ANALYSIS
5717             _When_(pointer == nullptr, _Analysis_noreturn_)
5718             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
5719             {
5720                 if (pointer == nullptr)
5721                 {
5722                     va_list argList;
5723                     va_start(argList, formatString);
5724                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList);
5725                 }
5726             }
5727 
5728             _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_)
5729             __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...)
5730             {
5731                 if (condition)
5732                 {
5733                     va_list argList;
5734                     va_start(argList, formatString);
5735                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5736                 }
5737                 return condition;
5738             }
5739 
5740             _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_)
5741             __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...)
5742             {
5743                 if (!condition)
5744                 {
5745                     va_list argList;
5746                     va_start(argList, formatString);
5747                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5748                 }
5749                 return condition;
5750             }
5751 
5752             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)>
5753             _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_)
5754             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...)
5755             {
5756                 if (pointer == nullptr)
5757                 {
5758                     va_list argList;
5759                     va_start(argList, formatString);
5760                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5761                 }
5762                 return pointer;
5763             }
5764 
5765             template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)>
5766             __WI_SUPPRESS_NULLPTR_ANALYSIS
5767             _When_(pointer == nullptr, _Analysis_noreturn_)
5768             __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...)
5769             {
5770                 if (pointer == nullptr)
5771                 {
5772                     va_list argList;
5773                     va_start(argList, formatString);
5774                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList);
5775                 }
5776             }
5777 
5778             _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_)
5779             __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...)
5780             {
5781                 if (FAILED_NTSTATUS(status))
5782                 {
5783                     va_list argList;
5784                     va_start(argList, formatString);
5785                     __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList);
5786                 }
5787                 return status;
5788             }
5789 #endif // WIL_ENABLE_EXCEPTIONS
5790 
5791         }   // __R_NS_NAME namespace
5792     }   // details namespace
5793     /// @endcond
5794 
5795 
5796     //*****************************************************************************
5797     // Error Handling Policies to switch between error-handling style
5798     //*****************************************************************************
5799     // The following policies are used as template policies for components that can support exception, fail-fast, and
5800     // error-code based modes.
5801 
5802     // Use for classes which should return HRESULTs as their error-handling policy
5803     // Intentionally removed logging from this policy as logging is more useful at the caller.
5804     struct err_returncode_policy
5805     {
5806         typedef HRESULT result;
5807 
5808         __forceinline static HRESULT Win32BOOL(BOOL fReturn) { RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn); return S_OK; }
5809         __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; RETURN_LAST_ERROR_IF_NULL_EXPECTED(h); return S_OK; }
5810         _Post_satisfies_(return == hr)
5811         __forceinline static HRESULT HResult(HRESULT hr) { return hr; }
5812         __forceinline static HRESULT LastError() { return wil::details::GetLastErrorFailHr(); }
5813         __forceinline static HRESULT LastErrorIfFalse(bool condition) { RETURN_LAST_ERROR_IF_EXPECTED(!condition); return S_OK; }
5814         _Post_satisfies_(return == S_OK)
5815         __forceinline static HRESULT OK() { return S_OK; }
5816     };
5817 
5818     // Use for classes which fail-fast on errors
5819     struct err_failfast_policy
5820     {
5821         typedef _Return_type_success_(true) void result;
5822         __forceinline static result Win32BOOL(BOOL fReturn) { FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); }
5823         __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; FAIL_FAST_LAST_ERROR_IF_NULL(h); }
5824         _When_(FAILED(hr), _Analysis_noreturn_)
5825         __forceinline static result HResult(HRESULT hr) { FAIL_FAST_IF_FAILED(hr); }
5826         __forceinline static result LastError() { FAIL_FAST_LAST_ERROR(); }
5827         __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { FAIL_FAST_LAST_ERROR(); } }
5828         __forceinline static result OK() {}
5829     };
5830 
5831 #ifdef WIL_ENABLE_EXCEPTIONS
5832     // Use for classes which should return through exceptions as their error-handling policy
5833     struct err_exception_policy
5834     {
5835         typedef _Return_type_success_(true) void result;
5836         __forceinline static result Win32BOOL(BOOL fReturn) { THROW_IF_WIN32_BOOL_FALSE(fReturn); }
5837         __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; THROW_LAST_ERROR_IF_NULL(h); }
5838         _When_(FAILED(hr), _Analysis_noreturn_)
5839         __forceinline static result HResult(HRESULT hr) { THROW_IF_FAILED(hr); }
5840         __forceinline static result LastError() { THROW_LAST_ERROR(); }
5841         __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { THROW_LAST_ERROR(); } }
5842         __forceinline static result OK() {}
5843     };
5844 #else
5845     // NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined
5846     // (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at
5847     // template instantiation time since this type lacks required member functions. An alternative would be to have some
5848     // 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available,
5849     // but that may have unexpected side effects when compiling code that expects to be using exceptions
5850     struct err_exception_policy
5851     {
5852     };
5853 #endif
5854 
5855 } // namespace wil
5856 
5857 #pragma warning(pop)
5858 
5859 #endif // defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE)
5860 #endif // __WIL_RESULTMACROS_INCLUDED
5861