You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5941 lines
306 KiB

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