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.

5843 lines
301KB

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