2011-05-13 37 views
1

我正在使用com-interop在c#中使用com對象。我爲對象提供了一個事件處理程序,它在完成它的事情後調用它。這是問題。我在拋出異常的處理一些理智檢查代碼,如果一切都沒有很好地與世界:來自COM事件處理程序的錯誤通知,使用互操作

_comObj.OnRequestCompleted += (int requestID, RequestStatus status) => 
{ 
    if (<sanity check fails>) 
     throw new Exception("This is insane!!!"); 

    ... 
} 

COM對象顯然是吞嚥那些例外,因爲我從來沒有看到他們在我的應用程序。我需要做些什麼來「表面」這些例外情況,以便在發生這種情況時得到通知?

回答

1

你可以使用Application.Current.Dispatcher.Invoke()方法,通過提供一個代理來拋出你的異常。

3

如果事件由COM服務器引發,這不是意外的行爲。異常不允許跨越COM分歧,對於異常沒有二進制互操作標準。 CLR在它的interop層安裝一個catch-all異常處理程序,這是調用你的事件處理程序的代碼。您提出的異常會轉換爲HRESULT,這是COM代碼報告失敗的標準方式。對於通用的Exception對象,這將是0x80131500。

接下來發生的事完全取決於COM服務器,它需要做一些有用的HRESULT。沒有看到它做任何事情都不是非常意外,函數調用返回值往往被忽略,尤其是通知樣式調用。你當然不會得到任何類似託管異常的東西。

如果可能的話,與COM組件供應商或作者一起工作。這種情況並不常見。除了記錄失敗之外,你可以做的事情並不多。調用Environment.Exit()如果這是一個不可能被忽略的嚴重問題。這與您的程序以未處理的異常終止並沒有任何區別。

0

如果您看一下由所有Visual Studio版本生成的標準C++ COM服務器實現(使用這種嚮導得到的結果:ATL Tutoral Step 5: Adding an Event),引發事件的C++代碼(在COM中命名爲「連接點」)條款)看起來像這樣。

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, &params, &varResult, NULL, NULL); 
    } 
    return hr; 
} 

所以,hr確實包含一個錯誤代碼,但在一般情況下,COM服務器實施者少了點

Fire_MyCustomEvent() 

因爲在一般情況下,可以有不止一個主叫方。如果一個呼叫者失敗,你會怎麼做?失敗所有人?在一般情況下,什麼都不是。在這裏看到這個有趣的討論類似的主題:Observers Should Never Throw Exceptions

這就是說,如果你自己的COM服務器,你可以調用錯誤,並且在這個例子中,傳遞EXCEPINFO作爲第七參數來調用。它將包含.NET異常文本「這是瘋了!!!」。

相關問題