COM開發拾粹<二> (轉)

worldblog發表於2007-12-14
COM開發拾粹 (轉)[@more@]

COM開發拾粹

5.自定義錯誤程式碼?HRESULT?異常?

COM中的出錯處理可以有多種選擇,比如用方法的[out,retval]引數返回自定義的錯誤程式碼;或返回標準的以及自定義的HRESULT值;丟擲異常也是一種選擇。採用哪種方法要根據實際情況而定。

返回自定義錯誤程式碼是一種源自C語言結構化設計的傳統方法,它放棄了C++以及COM的出錯處理機制,採用自建的處理方法。程式碼上少不了要寫很多的switch-case語句以捕捉錯誤程式碼進行處理。它的缺點是最外層程式碼要想得到最內層的錯誤的話,則中間層就必須如實的返回內層的出錯程式碼,這樣一層層的”抄送”給最外層。帶來的負作用就是靈活性非常差。

異常(exception)可以解決這個問題。但在COM規範裡規定,一個COM不能讓任何異常逃脫到這個COM之外,原因是你不知道這個COM的客戶端語言是否支援異常機制,它能不能捕獲(catch)到這個異常。規定是死的,人的活的。如果客戶端缺定也是C++編寫的,並且你也不需要編寫那麼”規範”的COM,而只要實用就行,那麼從COM裡丟擲異常,客戶端來捕獲又何妨?不過,這種”玩法”最好僅在程式內DLL中使用,跨程式、跨機器的異常能不能被正常捕獲,COM規範裡可沒承諾什麼,本來你就沒用COM的推薦方法嘛。

那什麼是COM的推薦方法,答案是HRESULT。我們可以返回一個HRESULT值表示某種錯誤。很多情況下,我們都懶得去查預定義的HRESULT值,更不願意自已定義HRESULT了,於是幾乎所有的方法都是返回S_OK或E_FAIL。其實32位長的HRESULT給我們留出了充足的空間來定義自已的錯誤碼。你可以把HRESULT值定義在IDL中,這樣當客戶端#import這個COM時,也會把定義自動加到*.tlh檔案中,無需附加的.h檔案宣告:

cpp_quote("//自定義錯誤碼"):namespace prefix = o ns = "urn:schemas--com::office" />

cpp_quote("#define E_IDNOTFOUND 0x8000F001")

cpp_quote("#define E_XIST 0x8000F002")

cpp_quote("#define E_IDREQUIRED 0x8000F003")

客戶端處理HRESULT值分為兩種情況。如果你用VC寫客戶端,用#import預編譯指令生成了COM的智慧封裝,那麼這個封裝會自動把錯誤的返回碼轉成一個異常丟擲。如下面是#import生成的封裝程式碼:

inline _variant_t IContext::GetContextValue ( _bstr_t PropName ) {

  VARIANT _result;

  VariantInit(&_result);

  HRESULT _hr = get_ContextValue(PropName, &_result); //呼叫真正的方法

  if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this)); //如果返回一個ERROR值,_com_issue_errorex就丟擲異常

  return _variant_t(_result, false);

}

這樣的封裝程式碼讓我們即可以享受到特定語言(C++)提供的便利,又可以在開發COM時遵守統一的規範而不需根據客戶端作特殊的處理。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993477/,如需轉載,請註明出處,否則將追究法律責任。

相關文章