COM组件设计与应用(十二)

COM组件设计与应用(十二)
错误与异常处理

作者:杨老师

下载源代码

一、前言

  程序设计中,错误处理必不可少,而且通常要占用很大的篇幅。本回书着落在 COM 中的错误(异常)的处理方法。
  在组件程序中,如果遇到错误,一般有两个方式进行处理。

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

E_INVALIDARG0x80070057参数错误
E_OUTOFMEMORY0x8007000E内存错误
E_NOTIMPL0x80004001未实现
E_POINTER0x80004003无效指针
E_HANDLE0x80070006无效句柄
E_ABORT0x80004004终止操作
E_ACCESSDENIED0x80070005拒绝访问
E_NOINTERFACE0x80004002不支持接口

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

参数含义值(二进制)

sev 严重程度

成功00
成功,但有一些报告信息01
警告10
错误11

fac 设备信息

FACILITY_AAF00000010010
FACILITY_ACS00000010100
FACILITY_BACKGROUNDCOPY00000100000
FACILITY_CERT00000001011
FACILITY_COMPLUS00000010001
FACILITY_CONFIGURATION00000100001
FACILITY_CONTROL00000001010
FACILITY_DISPATCH00000000010
FACILITY_DPLAY00000010101
FACILITY_HTTP00000011001
FACILITY_INTERNET00000001100
FACILITY_ITF00000000100
FACILITY_MEDIASERVER00000001101
FACILITY_MSMQ00000001110
FACILITY_NULL00000000000
FACILITY_RPC00000000001
FACILITY_SCARD00000010000
FACILITY_SECURITY00000001001
FACILITY_SETUPAPI00000001111
FACILITY_SSPI00000001001
FACILITY_STORAGE00000000011
FACILITY_SXS00000010111
FACILITY_UMI00000010110
FACILITY_URT00000010011
FACILITY_WIN3200000000111
FACILITY_WINDOWS00000001000
FACILITY_WINDOWS_CE00000011000

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 中,选中组件支持错误处理接口

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

 

本文属转载,原文见:http://www.vckbase.com/document/viewdoc/?id=1520

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值