To follow typical COM procedure, whenever any error occurs, one must do the following:
- Check the
HRESULTwithFAILEDor similar, to see if an error occured. - Create a variable to hold an
IErrorInfo(typicallyCComPtr<IErrorInfo>) - Call
::GetErrorInfo(0, &var). - Get the human readable version of that by calling
IErrorInfo::GetDescription. - Convert the
BSTRinto astd::wstring. - Convert the
std::wstringinto some form ofchar const*. - Throw a user defined exception type which derives from
std::exceptionwhich exposes bits 1, 5, and 6 above.
This all seems like a lot of boilerplate which has to go around pretty much every function call in COM.
I know the MSVC++ compiler provides a whole bunch of stuff to make messing with COM easier, such as ATL, and the compiler specific COM extensions _com_error, _com_raise_error and similar, but I’m not sure how to use these, or if they’re even intended to be used by user code.
Are there any typical strategies that are used to manage this complexity in an exception safe and race condition safe manner?
The “obvious” solution is a
ComException. It can handle pretty much all steps – you just need to get obtain theHRESULTfor the ctor and throw the resulting object (steps 1 and 7).You can even write
to take care of step 7 for you. E.g.
check(pUnk->QueryInterface(MyID, &pMyIf));