2012-09-25 66 views
6

如果Windows運行時類型引發COM錯誤,.NET似乎經常(或總是)將此錯誤包裝爲Exception實例。錯誤消息包括COM HRESULT錯誤代碼。例如,在AES-CBC中使用新的Cryptographic API時,錯誤的緩衝區長度會導致Exception帶有消息「提供的用戶緩衝區對於請求的操作無效(Exception from HRESULT: 0x800706F8)」。如何處理導致異常的WinRT異常?

那麼,我們應該如何處理這些例外?我們是否應該讀取來自異常的HRESULT代碼,以瞭解是什麼樣的異常?在經典的.NET中,我會得到一個CryptographicException,我可以用它來區分密碼錯誤和其他錯誤。

我不明白的另一件事是,Microsoft代碼質量規則聲明,不應該拋出異常,但總是派生類型。原因是,沒有人應該被迫抓住一般的Exception,以獲得更多致命的例外,如OutOfMemoryException。另一條規則是,永遠不要在圖書館抓到Exceptio n。如果我們被迫在Windows Store應用程序或WinRT庫中捕獲Exception,我們如何才能遵循這些策略?

順便說一句:Clemens Vasters shows in his blog how we can catch Exception while avoiding to catch fatal exception。我假設趕上Exception不再是壞代碼。

+0

對於鏈接的博客條目,託管代碼無法捕獲許多列出的「致命」異常。值得注意的是,'StackOverflowException',雖然我相當確定AVs不能被捕獲(兩者都可以在本地代碼中捕獲,當然,但這樣做是危險的)。還要注意的是,_appear_致命的一些例外事實上可能並非如此。例如,當特定緩衝區中的空間耗盡時,許多COM組件返回'E_OUTOFMEMORY'。該HRESULT將被轉換爲OutOfMemoryException,但這並不意味着該進程已經耗盡了其整個地址空間。 –

回答

4

有可能捕獲Exception,通過打開HRESULT來處理特定的錯誤,並且如果錯誤是「意外的」,則重新拋出Exception。例如,

try 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    switch (ex->HResult) 
    { 
    case E_INVALID_USER_BUFFER: // 0x800706f8 
     // handle invalid buffer case... 
     break; 
    default: 
     // Unexpected exception; re-throw: 
     throw; 
    } 
} 

(我要指出的是提供了一個無效的緩衝區聽起來更像是一個比一個運行時錯誤邏輯錯誤,所以我不知道這是否特定的異常應該被捕獲。)

或者,更通用的解決方案是編寫一個函數或一組函數來處理已知HRESULT的Exception並重新引發更具體的異常。例如,

static void HandleKnownExceptions(Action f) 
{ 
    try 
    { 
     f(); 
    } 
    catch (Exception ex) 
    { 
     // Detect expected HRESULTs and throw the more-specific exception 
     // type for each. 
    } 
} 

這兩種方法在C++和C#中都能很好地工作。

請注意,並不一定是由平臺或其他組件直接拋出Exception的情況。在Windows運行時ABI層,沒有例外:通過HRESULT在ABI邊界上報告所有錯誤。 CLR將一些已知的HRESULT轉換爲更具體的異常類型,但不能執行一般翻譯。

+0

謝謝詹姆斯。當捕獲無效緩衝區HRESULT時,這是我的方法。我覺得.NET程序員現在必須處理HRESULTS有點奇怪。當試圖解密可能被調節過的或僅僅被裁剪的無效數據時,你很容易得到一個無效的緩衝區。我認爲幾乎不可能檢查正確長度的加密數據,因爲這取決於使用的算法和密鑰。已經很難找到使用的塊大小。捕獲無效緩衝區錯誤對於確保以用戶友好的方式處理無效數據至關重要。 –

+0

啊,那我的錯誤。我誤解了什麼緩衝區是無效的。你是對的,處理這種錯誤是個好主意:-) –