HRESULT Information in Managed Code
The interaction between managed code and COM can cause problems when HRESULT return values are encountered.
In a COM interface, an HRESULT return value can play these roles:
Deliver error information (for example, E_INVALIDARG).
Deliver status information about normal program behavior.
When COM calls into managed code, HRESULTs can cause these problems:
COM functions that return HRESULT values less than zero (failure codes) generate exceptions.
Because many of the Visual Studio SDK COM functions either return HRESULT values less than zero or return different success codes, the Visual Studio SDK interop assemblies have been written so that the method signatures are preserved. All Visual Studio SDK interop methods are of int type. HRESULT values are passed through the interop layer without alteration and without generating exceptions.
Because a COM function returns an HRESULT to the managed method that calls it, the calling method must check the HRESULT and throw exceptions as necessary.
When you call a COM interface from managed code, examine the HRESULT value and throw an exception if required. The ErrorHandler class contains the ThrowOnFailure method, which throws a COM exception, depending on the value of the HRESULT passed to it.
By default, ThrowOnFailure throws an exception whenever it is passed an HRESULT that has a value less than zero. In cases where such HRESULTs are acceptable values and no exception should be thrown, the values of additional HRESULTS should be passed to ThrowOnFailure after the values are tested. If the HRESULT being tested matches any HRESULT values explicitly passed to ThrowOnFailure, no exception is thrown.
The VSConstants class contains constants for common HRESULTS, for example, S_OK and E_NOTIMPL, and Visual Studio HRESULTS, for example, VS_E_INCOMPATIBLEDOCDATA and VS_E_UNSUPPORTEDFORMAT. VSConstants also provides the Succeeded and Failed methods, which correspond to the SUCCEEDED and FAILED macros in COM.
For example, consider the following function call, in which E_NOTIMPL is an acceptable return value but any other HRESULT less than zero represents an error.
If there are more than one acceptable return values, additional HRESULT values can just be appended to the list in the call to ThrowOnFailure.
If no exception occurs, managed code returns S_OK to the COM function that called it. COM interop supports common exceptions that are strongly typed in managed code. For example, a method that receives an unacceptable null argument throws an ArgumentNullException.
If you are not certain which exception to throw, but you know the HRESULT you want to return to COM, you can use the ThrowExceptionForHR method to throw an appropriate exception. This works even with a nonstandard error, for example, VS_E_INCOMPATIBLEDOCDATA. ThrowExceptionForHR attempts to map the HRESULT passed to it to a strongly typed exception. If it cannot, it throws a generic COM exception instead. The ultimate result is that the HRESULT you pass to ThrowExceptionForHR from managed code is returned to the COM function that called it.
Exceptions compromise performance and are intended to indicate abnormal program conditions. Conditions that occur often should be handled inline, instead of a thrown exception.