COM組件設計與應用(十二)
錯誤與異常處理
作者:楊老師
下載源代碼
一、前言
程序設計中,錯誤處理必不可少,而且通常要占用很大的篇幅。本回書(shū)著(zhù)落在 COM 中的錯誤(異常)的處理方法。
在組件程序中,如果遇到錯誤,一般有兩個(gè)方式進(jìn)行處理。
二、簡(jiǎn)單返回
對于比較簡(jiǎn)單的錯誤,直接返回表示錯誤原因的 HRESULT。比如下面幾個(gè)就是常見(jiàn)的錯誤值:
| E_INVALIDARG | 0x80070057 | 參數錯誤 |
| E_OUTOFMEMORY | 0x8007000E | 內存錯誤 |
| E_NOTIMPL | 0x80004001 | 未實(shí)現 |
| E_POINTER | 0x80004003 | 無(wú)效指針 |
| E_HANDLE | 0x80070006 | 無(wú)效句柄 |
| E_ABORT | 0x80004004 | 終止操作 |
| E_ACCESSDENIED | 0x80070005 | 拒絕訪(fǎng)問(wèn) |
| E_NOINTERFACE | 0x80004002 | 不支持接口 |
另外,你還可以返回自己構造 HRESULT 錯誤值。方法是使用宏 MAKE_HRESULT(sev,fac,code)
| 參數 | 含義 | 值(二進(jìn)制) |
| sev 嚴重程度 | 成功 | 00 |
| 成功,但有一些報告信息 | 01 | |
| 警告 | 10 | |
| 錯誤 | 11 | |
| fac 設備信息 | FACILITY_AAF | 00000010010 |
| FACILITY_ACS | 00000010100 | |
| FACILITY_BACKGROUNDCOPY | 00000100000 | |
| FACILITY_CERT | 00000001011 | |
| FACILITY_COMPLUS | 00000010001 | |
| FACILITY_CONFIGURATION | 00000100001 | |
| FACILITY_CONTROL | 00000001010 | |
| FACILITY_DISPATCH | 00000000010 | |
| FACILITY_DPLAY | 00000010101 | |
| FACILITY_HTTP | 00000011001 | |
| FACILITY_INTERNET | 00000001100 | |
| FACILITY_ITF | 00000000100 | |
| FACILITY_MEDIASERVER | 00000001101 | |
| FACILITY_MSMQ | 00000001110 | |
| FACILITY_NULL | 00000000000 | |
| FACILITY_RPC | 00000000001 | |
| FACILITY_SCARD | 00000010000 | |
| FACILITY_SECURITY | 00000001001 | |
| FACILITY_SETUPAPI | 00000001111 | |
| FACILITY_SSPI | 00000001001 | |
| FACILITY_STORAGE | 00000000011 | |
| FACILITY_SXS | 00000010111 | |
| FACILITY_UMI | 00000010110 | |
| FACILITY_URT | 00000010011 | |
| FACILITY_WIN32 | 00000000111 | |
| FACILITY_WINDOWS | 00000001000 | |
| FACILITY_WINDOWS_CE | 00000011000 | |
| code 唯一錯誤碼 | 16位(bit) 你自己定義去吧 |
調用者得到返回的 HRESULT 值后,也可以使用宏 HRESULT_SEVERITY()、HRESULT_FACILITY()、HRESULT_CODE() 來(lái)取得sev錯誤程度、fac設備信息和 code 錯誤代碼。
三、錯誤信息接口
既然 COM 是靠各種各樣的接口來(lái)提供服務(wù)的,于是很自然地就會(huì )想到,是否有一個(gè)接口能夠提供更豐富的錯誤信息報告那?答案是:ISupportErrorInfo。下面這段代碼是使用 ISupportErrorInfo 的一般方法:
STDMETHODIMP Cxxx::fun(){... ... ... ...CComQIPtr< ICreateErrorInfo> spCEI;::CreateErrorInfo( &spCEI );spCEI->SetGUID( IID_Ixxx ); // 發(fā)生錯誤的接口IIDspCEI->SetSource( L"xxx.xxx" ); // ProgID// 如果你的組件同時(shí)提供了幫助文件,那么就可以:spCEI->SetHelpContext( 0 ); // 設置幫助文件的主題號spCEI->SetHelpFile( L"xxx.hlp" ); // 設置幫助文件的文件名spCEI->SetDescription( L"錯誤描述信息" );CComQIPtr < IErrorInfo > spErrInfo = spCEI;if( spErrInfo )::SetErrorInfo( 0, spErrInfo ); // 這時(shí)調用者就可以得到錯誤信息了return E_FAIL;} 上面是原理性代碼,在我們寫(xiě)的程序中,不用這么麻煩。因為 ATL 已經(jīng)把上述的代碼給我們包裝成 CComCoClass::Error() 的6個(gè)重載函數了。如此,我們可以非常簡(jiǎn)單的改寫(xiě)為:STDMETHODIMP Cxxx::fun(){... ... ... ...return Error( L"錯誤描述信息" );}四、關(guān)于 try/catch

HRESULT hr = spXXX->fun() // 調用組件功能if( FAILED( hr ) ) // 如果發(fā)生了錯誤{CComQIPtr < ISupportErrorInfo > spSEI = spXXX; // 組件是否提供了 ISupportErrorInfo 接口?if( spSEI ) // 如果支持,那么{hr = spSEI->InterfaceSupportsErrorInfo( IID_Ixxx ); // 是否支持 Ixxx 接口的錯誤處理?if( SUCCEEDED( hr ) ){ // 支持,太好了。取出錯誤信息CComQIPtr < IErrorInfo > spErrInfo; // 聲明 IErrorInfo 接口hr = ::GetErrorInfo( 0, &spErrInfo ); // 取得接口if( SUCCEEDED( hr ) ){CComBSTR bstrDes;spErrInfo->GetDescription( &bstrDes ); // 取得錯誤描述...... // 還可以取得其它的信息}}}} 2、如果使用 #import 等包裝方式調用組件,接收錯誤的方法是:try{...... // 調用組件功能}catch( _com_error &e ){e.Description(); // 取得錯誤描述信息...... // 還可以調用 _com_error 函數取得其它信息}六、編寫(xiě)支持錯誤處理的組件程序

聯(lián)系客服