我已經實作了IThumbnailProvider,它被編譯成一個 dll,然后使用regsvr32.
在代碼中,我使用了 STL 容器,例如std::vector:
std::vector<double> someRGBAccumulatorForDownsamplingToThumbnail = std::vector<double>(1234567);
因為 STL 容器主要是圍繞 RAII 構建的,所以不會對失敗的記憶體分配進行空值檢查。相反,上面的代碼會在記憶體不足的情況下拋出例外。發生這種情況時,我是否應該捕獲此例外以回傳HRESULT(背景關系:GetThumbnail的實作)?
try {
// ...
} catch (bad_alloc& ex) {
return E_OUTOFMEMORY;
}
或者 WINAPI 可以安全地處理我允許例外“冒泡”嗎?
我問是因為我正在閱讀 WINAPI 是基于 C 的,并且 C 沒有例外。
uj5u.com熱心網友回復:
IThumbnailProvider是一個COM介面。組件物件模型是一種與語言無關的協議,它描述(以及其他)客戶端和介面實作者之間的二進制契約。它建立了一個具有明確規則的邊界(應用程式二進制介面,ABI)1。
由于該協議與語言無關,因此允許通過 ABI 的內容僅限于最小公分母。它最終略低于 C 函式所稱的支持。任何特定于語言的構造(例如 C 例外)不得跨越 ABI。
在 C 中實作 COM 介面時,您必須確保 C 例外永遠不會穿過 ABI。您可以做的最低限度是將所有介面方法標記為noexcept:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
// ...
}
雖然這符合 COM 合同的所有要求,但通常不希望有一個未捕獲的例外導致 COM 物件所在的整個程序中斷。
一個更復雜的解決方案將捕獲所有例外并將它們轉換為HRESULT錯誤代碼(請參閱COM 中的錯誤處理),類似于有問題的代碼所做的:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
} catch(...) {
return E_FAIL;
}
}
同樣,這是完全有效的,盡管任何 COM 開發人員都害怕看到0x80004005錯誤代碼,這在語意上等同于“出錯了”。在嘗試診斷問題時幾乎沒有用。
更有用的實作將嘗試將某些眾所周知的 C 例外型別映射到標準HRESULT值(例如std::bad_alloc->E_OUTOFMEMORY或std::system_error呼叫的結果HRESULT_FROM_WIN32)。雖然可以在每個介面方法實作上手動實作catch-cascade,但已經有一些庫可以為您完成。Windows 實作庫 (WIL)為此目的提供了例外保護,使您的代碼不包含細節。
以下是使用 WIL 的可能介面方法實作:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
}
CATCH_RETURN();
}
順便說一句,我保留noexcept后兩種實作的說明符僅作為防御措施;它們不是嚴格要求的,但要保持介面有效,以防將來實作更改以允許 C 例外逃逸。
1 我不知道有一份正式檔案闡明了這些規則。我們必須假設編譯器是規范。順便說一句,微軟的 C 和 C 編譯器不同意,Direct2D 團隊發現了這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/511446.html
標籤:C 例外温纳皮记不清结果
