//********************************************************* // // Copyright (c) Microsoft. All rights reserved. // This code is licensed under the MIT License. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. // //********************************************************* //! @file //! WIL Error Handling Helpers: supporting file defining a family of macros and functions designed to uniformly handle errors //! across return codes, fail fast, exceptions and logging for Win32 error codes. #ifndef __WIL_WIN32_RESULTMACROS_INCLUDED #define __WIL_WIN32_RESULTMACROS_INCLUDED #include "result_macros.h" // Helpers for return macros /// @cond #define __WIN32_RETURN_WIN32(error, str) \ __WI_SUPPRESS_4127_S do \ { \ const auto __error = (error); \ if (FAILED_WIN32(__error)) \ { \ __R_FN(Return_Win32)(__R_INFO(str) __error); \ } \ return __error; \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define __WIN32_RETURN_GLE_FAIL(str) return __R_FN(Win32_Return_GetLastError)(__R_INFO_ONLY(str)) FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr) { if (SUCCEEDED(hr)) { return ERROR_SUCCESS; } return HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr; } /// @endcond //***************************************************************************** // Macros for returning failures as WIN32 error codes //***************************************************************************** // Always returns a known result (WIN32 error code) - always logs failures #define WIN32_RETURN_WIN32(error) __WIN32_RETURN_WIN32(wil::verify_win32(error), #error) #define WIN32_RETURN_LAST_ERROR() __WIN32_RETURN_GLE_FAIL(nullptr) // Conditionally returns failures (WIN32 error code) - always logs failures #define WIN32_RETURN_IF_WIN32_ERROR(error) \ __WI_SUPPRESS_4127_S do \ { \ const auto __errorRet = wil::verify_win32(error); \ if (FAILED_WIN32(__errorRet)) \ { \ __WIN32_RETURN_WIN32(__errorRet, #error); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_WIN32_IF(error, condition) \ __WI_SUPPRESS_4127_S do \ { \ if (wil::verify_bool(condition)) \ { \ __WIN32_RETURN_WIN32(wil::verify_win32(error), #condition); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_WIN32_IF_NULL(error, ptr) \ __WI_SUPPRESS_4127_S do \ { \ if ((ptr) == nullptr) \ { \ __WIN32_RETURN_WIN32(wil::verify_win32(error), #ptr); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_LAST_ERROR_IF(condition) \ __WI_SUPPRESS_4127_S do \ { \ if (wil::verify_bool(condition)) \ { \ __WIN32_RETURN_GLE_FAIL(#condition); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_LAST_ERROR_IF_NULL(ptr) \ __WI_SUPPRESS_4127_S do \ { \ if ((ptr) == nullptr) \ { \ __WIN32_RETURN_GLE_FAIL(#ptr); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) // Conditionally returns failures (WIN32 error code) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern #define WIN32_RETURN_IF_WIN32_ERROR_EXPECTED(error) \ __WI_SUPPRESS_4127_S do \ { \ const auto __errorRet = wil::verify_win32(error); \ if (FAILED_WIN32(__errorRet)) \ { \ return __errorRet; \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_WIN32_IF_EXPECTED(error, condition) \ __WI_SUPPRESS_4127_S do \ { \ if (wil::verify_bool(condition)) \ { \ return wil::verify_win32(error); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_WIN32_IF_NULL_EXPECTED(error, ptr) \ __WI_SUPPRESS_4127_S do \ { \ if ((ptr) == nullptr) \ { \ return wil::verify_win32(error); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_LAST_ERROR_IF_EXPECTED(condition) \ __WI_SUPPRESS_4127_S do \ { \ if (wil::verify_bool(condition)) \ { \ return wil::verify_win32(wil::details::GetLastErrorFail()); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) #define WIN32_RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) \ __WI_SUPPRESS_4127_S do \ { \ if ((ptr) == nullptr) \ { \ return wil::verify_win32(wil::details::GetLastErrorFail()); \ } \ } \ __WI_SUPPRESS_4127_E while ((void)0, 0) //***************************************************************************** // Macros to catch and convert exceptions on failure //***************************************************************************** // Use these macros *within* a catch (...) block to handle exceptions #define WIN32_RETURN_CAUGHT_EXCEPTION() return __R_FN(Win32_Return_CaughtException)(__R_INFO_ONLY(nullptr)) // Use these macros in place of a catch block to handle exceptions #define WIN32_CATCH_RETURN() \ catch (...) \ { \ WIN32_RETURN_CAUGHT_EXCEPTION(); \ } namespace wil { //***************************************************************************** // Public Helpers that catch -- mostly only enabled when exceptions are enabled //***************************************************************************** // Win32ErrorFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally // it re-throws and catches the exception to convert it to a WIN32 error code. If an exception is of an unrecognized type // the function will fail fast. // // try // { // // Code // } // catch (...) // { // status = wil::Win32ErrorFromCaughtException(); // } _Always_(_Post_satisfies_(return > 0)) __declspec(noinline) inline long Win32ErrorFromCaughtException() WI_NOEXCEPT { return __WIN32_FROM_HRESULT(ResultFromCaughtException()); } /// @cond namespace details::__R_NS_NAME { #ifdef WIL_ENABLE_EXCEPTIONS __R_DIRECT_METHOD(long, Win32_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT { __R_FN_LOCALS; return __WIN32_FROM_HRESULT(wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY)); } #endif __R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT { __R_FN_LOCALS; return __WIN32_FROM_HRESULT(wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY)); } } // namespace details::__R_NS_NAME /// @endcond } // namespace wil #endif // __WIL_WIN32_RESULTMACROS_INCLUDED