• 【转载】COM 组件设计与应用(十二)——错误与异常处理


    原文:http://vckbase.com/index.php/wv/1238.html

    一、前言

    程序设计中,错误处理必不可少,而且通常要占用很大的篇幅。本回书着落在 COM 中的错误(异常)的处理方法。

    在组件程序中,如果遇到错误,一般有两个方式进行处理。

    二、简单返回

    对于比较简单的错误,直接返回表示错误原因的 HRESULT。比如下面几个就是常见的错误值: 

    E_INVALIDARG 0x80070057 参数错误
    E_OUTOFMEMORY 0x8007000E 内存错误
    E_NOTIMPL 0x80004001 未实现
    E_POINTER 0x80004003 无效指针
    E_HANDLE 0x80070006 无效句柄
    E_ABORT 0x80004004 终止操作
    E_ACCESSDENIED 0x80070005 拒绝访问
    E_NOINTERFACE 0x80004002 不支持接口

    另外,你还可以返回自己构造 HRESULT 错误值。方法是使用宏 MAKE_HRESULT(sev,fac,code) 

    参数 含义 值(二进制)

    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() 来取得sev错误程度、fac设备信息和 code 错误代码。

    三、错误信息接口

    既然 COM 是靠各种各样的接口来提供服务的,于是很自然地就会想到,是否有一个接口能够提供更丰富的错误信息报告那?答案是:ISupportErrorInfo。下面这段代码是使用 ISupportErrorInfo 的一般方法:

    STDMETHODIMP Cxxx::fun()
    {
    	... ... ... ...
    
    	CComQIPtr< ICreateErrorInfo> spCEI;
    	::CreateErrorInfo( &spCEI );
    
    	spCEI->SetGUID( IID_Ixxx );		// 发生错误的接口IID
    		
    	spCEI->SetSource( L"xxx.xxx" );	// ProgID
    
    	// 如果你的组件同时提供了帮助文件,那么就可以:
    	spCEI->SetHelpContext( 0 );		// 设置帮助文件的主题号
    	spCEI->SetHelpFile( L"xxx.hlp" );	// 设置帮助文件的文件名
    
    	spCEI->SetDescription( L"错误描述信息" );
    
    	CComQIPtr < IErrorInfo > spErrInfo = spCEI;
    	if( spErrInfo )
    	  ::SetErrorInfo( 0, spErrInfo );	// 这时调用者就可以得到错误信息了
    
    	return E_FAIL;
    }
    

      

    上面是原理性代码,在我们写的程序中,不用这么麻烦。因为 ATL 已经把上述的代码给我们包装成 CComCoClass::Error() 的6个重载函数了。如此,我们可以非常简单的改写为:

    STDMETHODIMP Cxxx::fun()
    {
    	... ... ... ...
    
    	return Error( L"错误描述信息" );
    }
    

      

    四、关于 try/catch

    学习了 C++ 后,很多人都喜欢使用 try/catch 的异常处理结构。如果你使用 vc6.0 的ATL,编译器默认是不支持异常处理的,编译后会报告“warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX”,解决方法是手工加上编译开关:

    图一、加上编译开关,支持C++的异常处理结构

    在vc.net 2003 中,编译器默认是支持异常处理结构的,所以不用特别进行设置。如果想减小目标文件的尺寸,你也可以决定不使用 C++ 异常处理,那么在项目属性中

    图二、在vc.net中修改是否支持C++异常结构的编译开关

    五、客户端接收组件的错误信息

    1、如果使用 API 方式调用组件,接收错误的方法是:

    HRESULT hr = spXXX->fun()	// 调用组件功能
    if( FAILED( hr ) )	// 如果发生了错误
    {
    	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 函数取得其它信息
    }
    

      

    六、编写支持错误处理的组件程序

    非常简单,只要在增加 ATL 组件对象的时候选中 ISupportErrorInfo 即可。

    图三、vc6.0 中,选中组件支持错误处理接口

    图四、vc.net 2003 中,选中组件支持错误处理接口

    七、小结

    阅读文章后,请下载本回的示例程序。示例程序中演示了三种错误处理方法和三种接收错误的方法,同时程序中也有比较详细的注释。

  • 相关阅读:
    [转]scrapy中的request.meta
    Item Pipeline
    scrapy spider官方文档
    scrapy选择器主要用法
    scrapy 选择器官方文档
    【bzoj3514】Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树
    【bzoj3813】奇数国 线段树
    【loj6177】「美团 CodeM 初赛 Round B」送外卖2 Floyd+状压dp
    【bzoj4499】线性函数 线段树
    【bzoj1018】[SHOI2008]堵塞的交通traffic 线段树区间合并+STL-set
  • 原文地址:https://www.cnblogs.com/zhehan54/p/5024415.html
Copyright © 2020-2023  润新知