mirror of
https://github.com/libretro/dolphin
synced 2024-11-04 20:43:51 -05:00
252 lines
9.3 KiB
C++
252 lines
9.3 KiB
C++
//*********************************************************
|
|
//
|
|
// 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.
|
|
//
|
|
//*********************************************************
|
|
#ifndef __WIL_CPPWINRT_INCLUDED
|
|
#define __WIL_CPPWINRT_INCLUDED
|
|
|
|
#include "common.h"
|
|
#include <windows.h>
|
|
#include <unknwn.h>
|
|
#include <hstring.h>
|
|
|
|
// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to
|
|
// understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to
|
|
// C++/WinRT "2.0" this was accomplished by injecting the WINRT_EXTERNAL_CATCH_CLAUSE macro - that WIL defines below -
|
|
// into its exception handler (winrt::to_hresult). Starting with C++/WinRT "2.0" this mechanism has shifted to a global
|
|
// function pointer - winrt_to_hresult_handler - that WIL sets automatically when this header is included and
|
|
// 'CPPWINRT_SUPPRESS_STATIC_INITIALIZERS' is not defined.
|
|
|
|
/// @cond
|
|
namespace wil::details
|
|
{
|
|
// Since the C++/WinRT version macro is a string...
|
|
inline constexpr int major_version_from_string(const char* versionString)
|
|
{
|
|
int result = 0;
|
|
auto str = versionString;
|
|
while ((*str >= '0') && (*str <= '9'))
|
|
{
|
|
result = result * 10 + (*str - '0');
|
|
++str;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
/// @endcond
|
|
|
|
#ifdef CPPWINRT_VERSION
|
|
// Prior to C++/WinRT "2.0" this header needed to be included before 'winrt/base.h' so that our definition of
|
|
// 'WINRT_EXTERNAL_CATCH_CLAUSE' would get picked up in the implementation of 'winrt::to_hresult'. This is no longer
|
|
// problematic, so only emit an error when using a version of C++/WinRT prior to 2.0
|
|
static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2,
|
|
"Please include wil/cppwinrt.h before including any C++/WinRT headers");
|
|
#endif
|
|
|
|
// NOTE: Will eventually be removed once C++/WinRT 2.0 use can be assumed
|
|
#ifdef WINRT_EXTERNAL_CATCH_CLAUSE
|
|
#define __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 1
|
|
#else
|
|
#define WINRT_EXTERNAL_CATCH_CLAUSE \
|
|
catch (const wil::ResultException& e) \
|
|
{ \
|
|
return winrt::hresult_error(e.GetErrorCode(), winrt::to_hstring(e.what())).to_abi(); \
|
|
}
|
|
#endif
|
|
|
|
#include "result_macros.h"
|
|
#include <winrt/base.h>
|
|
|
|
#if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE
|
|
static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2,
|
|
"C++/WinRT external catch clause already defined outside of WIL");
|
|
#endif
|
|
|
|
// In C++/WinRT 2.0 and beyond, this function pointer exists. In earlier versions it does not. It's much easier to avoid
|
|
// linker errors than it is to SFINAE on variable existence, so we declare the variable here, but are careful not to
|
|
// use it unless the version of C++/WinRT is high enough
|
|
extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept;
|
|
|
|
/// @cond
|
|
namespace wil::details
|
|
{
|
|
inline void MaybeGetExceptionString(
|
|
const winrt::hresult_error& exception,
|
|
_Out_writes_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars)
|
|
{
|
|
if (debugString)
|
|
{
|
|
StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str());
|
|
}
|
|
}
|
|
|
|
inline HRESULT __stdcall ResultFromCaughtException_CppWinRt(
|
|
_Inout_updates_opt_(debugStringChars) PWSTR debugString,
|
|
_When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars,
|
|
_Inout_ bool* isNormalized) noexcept
|
|
{
|
|
if (g_pfnResultFromCaughtException)
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
*isNormalized = true;
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.GetErrorCode();
|
|
}
|
|
catch (const winrt::hresult_error& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.code().value;
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
catch (const std::out_of_range& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_BOUNDS;
|
|
}
|
|
catch (const std::invalid_argument& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_INVALIDARG;
|
|
}
|
|
catch (...)
|
|
{
|
|
auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const ResultException& exception)
|
|
{
|
|
*isNormalized = true;
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.GetErrorCode();
|
|
}
|
|
catch (const winrt::hresult_error& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return exception.code().value;
|
|
}
|
|
catch (const std::bad_alloc& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
catch (const std::out_of_range& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_BOUNDS;
|
|
}
|
|
catch (const std::invalid_argument& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return E_INVALIDARG;
|
|
}
|
|
catch (const std::exception& exception)
|
|
{
|
|
MaybeGetExceptionString(exception, debugString, debugStringChars);
|
|
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION);
|
|
}
|
|
catch (...)
|
|
{
|
|
// Fall through to returning 'S_OK' below
|
|
}
|
|
}
|
|
|
|
// Tell the caller that we were unable to map the exception by succeeding...
|
|
return S_OK;
|
|
}
|
|
}
|
|
/// @endcond
|
|
|
|
namespace wil
|
|
{
|
|
inline std::int32_t __stdcall winrt_to_hresult(void* returnAddress) noexcept
|
|
{
|
|
// C++/WinRT only gives us the return address (caller), so pass along an empty 'DiagnosticsInfo' since we don't
|
|
// have accurate file/line/etc. information
|
|
return static_cast<std::int32_t>(details::ReportFailure_CaughtException<FailureType::Return>(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress)));
|
|
}
|
|
|
|
inline void WilInitialize_CppWinRT()
|
|
{
|
|
details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt;
|
|
if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2)
|
|
{
|
|
WI_ASSERT(winrt_to_hresult_handler == nullptr);
|
|
winrt_to_hresult_handler = winrt_to_hresult;
|
|
}
|
|
}
|
|
|
|
/// @cond
|
|
namespace details
|
|
{
|
|
#ifndef CPPWINRT_SUPPRESS_STATIC_INITIALIZERS
|
|
WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "0")
|
|
WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_CppWinRT, []
|
|
{
|
|
::wil::WilInitialize_CppWinRT();
|
|
return 1;
|
|
});
|
|
#else
|
|
WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1")
|
|
#endif
|
|
}
|
|
/// @endcond
|
|
|
|
// Provides an overload of verify_hresult so that the WIL macros can recognize winrt::hresult as a valid "hresult" type.
|
|
inline long verify_hresult(winrt::hresult hr) noexcept
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience.
|
|
template <typename T>
|
|
auto get_abi(T const& object) noexcept
|
|
{
|
|
return winrt::get_abi(object);
|
|
}
|
|
|
|
inline auto get_abi(winrt::hstring const& object) noexcept
|
|
{
|
|
return static_cast<HSTRING>(winrt::get_abi(object));
|
|
}
|
|
|
|
template <typename T>
|
|
auto put_abi(T& object) noexcept
|
|
{
|
|
return winrt::put_abi(object);
|
|
}
|
|
|
|
inline auto put_abi(winrt::hstring& object) noexcept
|
|
{
|
|
return reinterpret_cast<HSTRING*>(winrt::put_abi(object));
|
|
}
|
|
}
|
|
|
|
#endif // __WIL_CPPWINRT_INCLUDED
|