|
- //*********************************************************
- //
- // 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.
- //
- //*********************************************************
-
- // Note: When origination is enabled by including this file, origination is done as part of the RETURN_* and THROW_* macros. Before originating
- // a new error we will observe whether there is already an error payload associated with the current thread. If there is, and the HRESULTs match,
- // then a new error will not be originated. Otherwise we will overwrite it with a new origination. The ABI boundary for WinRT APIs will check the
- // per-thread error information. The act of checking the error clears it, so there should be minimal risk of failing to originate distinct errors
- // simply because the HRESULTs match.
- //
- // For THROW_ macros we will examine the thread-local error storage once per throw. So typically once, with additional calls if the exception is
- // caught and re-thrown.
- //
- // For RETURN_ macros we will have to examine the thread-local error storage once per frame as the call stack unwinds. Because error conditions
- // -should- be uncommon the performance impact of checking TLS should be minimal. The more expensive part is originating the error because it must
- // capture the entire stack and some additional data.
-
- #ifndef __WIL_RESULT_ORIGINATE_INCLUDED
- #define __WIL_RESULT_ORIGINATE_INCLUDED
-
- #include "result.h"
- #include <OleAuto.h> // RestrictedErrorInfo uses BSTRs :(
- #include "resource.h"
- #include "com.h"
- #include <roerrorapi.h>
-
- #ifndef __cplusplus_winrt // The CX runtime likes to originate errors already so we would conflict with them.
- namespace wil
- {
- namespace details
- {
- // Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame.
- inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT
- {
- if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception))
- {
- bool shouldOriginate = true;
-
- wil::com_ptr_nothrow<IRestrictedErrorInfo> restrictedErrorInformation;
- if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK)
- {
- // This thread already has an error origination payload. Don't originate again if it has the same HRESULT that we are
- // observing right now.
- wil::unique_bstr descriptionUnused;
- HRESULT existingHr = failure.hr;
- wil::unique_bstr restrictedDescriptionUnused;
- wil::unique_bstr capabilitySidUnused;
- if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)))
- {
- shouldOriginate = (failure.hr != existingHr);
- }
- }
-
- if (shouldOriginate)
- {
- #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
- wil::unique_hmodule errorModule;
- if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule))
- {
- auto pfn = reinterpret_cast<decltype(&::RoOriginateError)>(GetProcAddress(errorModule.get(), "RoOriginateError"));
- if (pfn != nullptr)
- {
- pfn(failure.hr, nullptr);
- }
- }
- #else // DESKTOP | SYSTEM
- ::RoOriginateError(failure.hr, nullptr);
- #endif // DESKTOP | SYSTEM
- }
- else if (restrictedErrorInformation)
- {
- // GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was already present,
- // then we need to restore the error information for later observation.
- SetRestrictedErrorInfo(restrictedErrorInformation.get());
- }
- }
- }
- } // namespace details
- } // namespace wil
-
- // Automatically call RoOriginateError upon error origination by including this file
- WI_HEADER_INITITALIZATION_FUNCTION(ResultStowedExceptionInitialize, []
- {
- ::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions);
- return 1;
- });
- #endif // __cplusplus_winrt
-
- #endif // __WIL_RESULT_ORIGINATE_INCLUDED
|