问题
I'm consuming a com object in c#, using com-interop. I provide an event handler to the object, which it calls after doing its thing. Here's the problem. I have some sanity-check code in the handler that throws an exception if all is not well with the world:
_comObj.OnRequestCompleted += (int requestID, RequestStatus status) =>
{
if (<sanity check fails>)
throw new Exception("This is insane!!!");
...
}
The com object is apparently swallowing those exceptions, because I never see them in my app. What do I need to do to "surface" those exceptions so that I am notified when they occur?
回答1:
This is not unexpected behavior if the event is raised by the COM server. Exceptions are not allowed to cross the COM divide, there is no binary interop standard for exceptions. The CLR installs a catch-all exception handler in its interop layer, the code that calls your event handler. The exception you raised is translated to an HRESULT, the standard way in which COM code reports failure. Which will be 0x80131500 for a generic Exception object.
What happens next is entirely up to the COM server, it needs to do something useful with the HRESULT it got. Not seeing it do anything it all is not terribly unexpected, function call return values are often ignored, especially so with notification style calls. You certainly won't get anything resembling a managed exception.
Work with the COM component vendor or author to work something out, if possible. Which isn't very often the case. Not much you can do beyond just logging the failure then. Call Environment.Exit() if this is a gross problem that cannot possibly be ignored. This isn't really any different from having your program terminated with an unhandled exception.
回答2:
You could use the Application.Current.Dispatcher.Invoke()
method, by supplying a delegate in which you throw your exception.
回答3:
If you look at the standard C++ COM server implementation that's generated by all Visual Studio versions (what you get using the wizards like this: ATL Tutoral Step 5: Adding an Event), the C++ code for raising an event (named a "connection point" in COM terms) looks like this.
HRESULT Fire_MyCustomEvent()
{
...
for (int iConnection = 0; iConnection < cConnections; iConnection++)
{
CComVariant varResult;
DISPPARAMS params = { NULL, NULL, 0, 0 };
hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL);
}
return hr;
}
So, hr
does contain an error code but in general, the COM server implementer just does
Fire_MyCustomEvent()
Because in general, there can be more than one caller. What would you do if one caller fail? Fail everyone? In the general case, nothing. See this interesting discussion here on a similar subject: Observers Should Never Throw Exceptions
That said, if you own the COM server, you can catch Invoke error, and in this example, pass EXCEPINFO as the 7th argument to invoke. It will contain the .NET Exception text "This is insane!!!".
来源:https://stackoverflow.com/questions/5996732/error-notification-from-com-event-handler-using-interop