There are two ways to throw an exception in C++/WinRT. You can throw the exception object directly:
throw winrt::hresult_invalid_argument(); throw winrt::hresult_error(D3DERR_DEVICELOST);
Or you can use the throw_hresult
function.
winrt::throw_hresult(E_INVALIDARG); winrt::throw_hresult(D3DERR_DEVICELOST);
What’s the difference?
If you look at the code for the throw_hresult
function, you’ll see that it eventually throws the underlying exception object, but it constructs the exception object with the take_
parameter. So the real question is “What does the take_
parameter do?”
The take_
parameter means that this exception is taking over the error context from the existing ABI error context. The error context is what is used by error reporting tools and debuggers to show the root cause of the error.
So it boils down to this:
- If this error was detected by your code, then you want the debugger and other error reporting tools to point to your code as the source of the error, and you should use
throw winrt::hresult_error
or a specific derived exception type if applicable, such ashresult_
.invalid_ argument - If you are propagating an error received by another component, then you want the debugger and other error reporting tools to direct the developer to the component from which you received the error. In that case, you should use
winrt::throw_hresult
.
Note that in the second case (propagation), the component you received the error from could itself be propagating an error from yet another component. As long as everybody propagates the error context along with the error, the debugging tools will point at the code that originated the error.¹
¹ The intermediate components are also reported, so you can also follow how the error traveled from the originator to the final destination, but the origination usually gives you the best information about what went wrong.²
² Propagating and transforming error context brings us full circle to the very early days of COM when HRESULT was a handle to an error object. The old new thing has become the new old thing.
Do exceptions in C++/WinRT not have an equivalent to .NET’s InnerException property?
So
winrt::throw_hresult
really should have been namedwinrt::rethrow
?Or there could be a context parameter which lets you specify your own context (I have detected the problem, I know who caused it and it’s not me), which defaults to null, which means “use existing”.
Randall Munroe has the answer, as usual: https://xkcd.com/1188/