.NET will automatically convert an HRESULT into a specific type of Exception based on the HRESULT. This is fine for many of the built-in HRESULTs closely related to Win32 API like function calls. In my case though, I wanted to turn an application specific error that occurs in an ATL COM server (ATL3.0 no less!) into a pretty Exception so that managed code would get a useful error message.
To do this:
- Create an empty error object via CreateErrorInfo( &pcerrInfo )
- Set the description via pcerrInfo->SetDescription(). CreateErrorInfo allocates a pointer to an object that implements ICreateErrorInfo. SetDescription() is a method defined on ICreateErrorInfo. Whatever gets set here will be assigned to the .NET Exception.Message property.
- call SetErrorInfo(0, perrInfo) where perrInfo is a pointer to IErrorInfo.
- To get perrInfo pointer, call pcerrInfo->QueryInterface(IID_IErrorInfo, (LPVOID*) &perrInfo);
- SetErroInfo() sets the error object for the current thread (actually it clears the current error object then sets it to the new one).
- after Release()-ing both pointers, return an error HRESULT (e.g., return E_FAIL).
- Don't make any other COM calls before returning the HRESULT as these might overwrite the error object just set.
- In .NET this will show up as a COMException where COMException.Message = IErrorInfo->GetDescription()
Since this will be used a lot, I put it into a single function that takes a string. In practice, I immediately return an error HRESULT after calling the function.
void
CSimpleTestObj::AppSetErrorInfo(LPWSTR pszErr)
{
ICreateErrorInfo *pcerrinfo;
IErrorInfo *perrinfo;
HRESULT hr;
hr = CreateErrorInfo(&pcerrinfo); // create generic error object
if
(SUCCEEDED(hr))
{
// set the
text - in .NET this will map to Exception.Message
pcerrinfo->SetDescription(pszErr);
// need to
get IErrorInfo because this is what the .NET code will see
hr =
pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);
if
(SUCCEEDED(hr))
{
// SetErrorInfo sets the
error object for the current thread
// .Net will take it,
make an exception,
// then set
ApplicationException.Message = IErrorInfo.GetDescription()
SetErrorInfo(0, perrinfo);
perrinfo->Release();
}
pcerrinfo->Release();
}
}
No comments:
Post a Comment