COMException error messages

Quick caveat; I am not a hardcore COM guy.  I do work with COM quite a bit but most of it is hobbyist work at home.  So if I make any COM errors here please let me know and I will correct them. Now onto the fun stuff.

Pure COM uses HRESULTS to indicate the success or failure of a method.  HRESULTS are just DWORDs under the cover.  They use the highest bit to indicate success or failure (0 is success) and the rest of the code is used to indicate the reason for failure/success.  Managed code on the other hand prefers to use Exceptions.  The CLR merges these somewhat conflicting paradigms by coverting failing HRESULTS into COM Exceptions when an interop call is made.  You can access the HRESULT from the exception. 

Typically when a COMException occurs you will usually get a generic error message like the following. 

   “Error HRESULT E_FAIL has been returned from a call to a COM component.”

Seeing this you would expect that the CLR just adds a generic error message to all COMExpcetions using a format string.  However, if you’ve done much interop programming, you’ve noticed that sometimes you’ll get error codes like E_FAIL but a completely different message (and usually its pretty helpful).  So how does that rich error information get in there?

As COM programmers surely know, rich error descriptions have been around in COM since OLE through the use of ISupportErrorInfo, IErrorInfo.  and the GetErrorInfo()/SetErrorInfo() pair of methods. 

When thet CLR encounters a failing HRESULT it will first grab error information via GetErrorInfo().  If error information is present it will then query the COM component on which the call was made and QueryInterface for ISupportErrorInfo.  If the coclass supports this interface the CLR will then populate the COMException from the information contained in IErrorInfo. 

Note that the original target of the COM call must implement ISupportErrorInfo for this to work.  If you have the following situation …

   Managed          |        Native

    Client        ->          IStore::GetPrice()     —>  IDatalayer::LookupItem()

Assume that the call to IDatalayer::LookupItem() fails with E_FAIL and it sets a rich error message via SetErrorInfo() and implements ISupportErrorInfo.  IStore::GetPrice() recieving this code, passes it back to the caller.  Assume also that IStore does not implement ISupportErrorInfo.  In this case, the CLR will fail in its attempt to QueryInterface on IStore and will return a generic error message. 

If IStore did implement ISupportErrorInfo, the CLR would use the IErrorInfo structure to create the exception. 

Helpful links

HRESULT Structure

COM Exception Class:


Comments (4)

  1. If you decide to support error info, make sure you call SetErrorInfo whenever *any* of the methods in your interface fail, without any exceptions. Even if a method simply returns E_NOTIMPL, you must call SetErrorInfo before doing that.

    I used to think that nothing really bad could happen if you claimed to support IErrorInfo on an interface and forgot to actually set error info on failure. Turns out this is not the case. CLR code that generates COMExceptions gets really confused when it stumbles upon a COM object that does this. As a result CLR can in certain situations throw a wrong exception type (e.g. instead of throwing a COMException it might throw some application-defined exception).

    This can have really bad consequences. In my case, some internal ADSI object used by System.DirectoryServices had this bug and it was casuing random breaks while doing directory searches. The only workaround I could find was to pinvoke SetErrorInfo(NULL) before making DirectoryServices calls.

  2. This is a follow up to an earlier post about COMException error messages.