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

七、小结

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

【转载】COM 组件设计与应用(十二)——错误与异常处理的更多相关文章

  1. AngularJs的UI组件ui-Bootstrap分享(十二)——Rating

    Rating是一个用于打分或排名的控件.看一个最简单的例子: <!DOCTYPE html> <html ng-app="ui.bootstrap.demo" x ...

  2. 2017-2018-1 《Linux内核原理与设计》第十二周作业

    <linux内核原理与设计>第十二周作业 Sql注入基础原理介绍 分组: 和20179215袁琳完成实验 一.实验说明   SQL注入攻击通过构建特殊的输入作为参数传入Web应用程序,而这 ...

  3. 【转载】COM 组件设计与应用(二)——GUID 和 接口

    原文:http://vckbase.com/index.php/wv/1203.html COM 组件设计与应用 系列文章:http://vckbase.com/index.php/piwz?& ...

  4. Bootstrap组件福利篇:十二款好用的组件推荐

    阅读目录 一.时间组件 1.效果展示 2.源码说明 3.代码示例 二.自增器组件 1.效果展示 2.源码说明 3.代码示例 三.加载效果 一.实用型 二.炫酷型 四.流程图小插件 1.效果展示 2.源 ...

  5. HT图形组件设计之道(二)

    上一篇我们自定义CPU和内存的展示界面效果,这篇我们将继续采用HT完成一个新任务:实现一个能进行展开和合并切换动作的刀闸控件.对于电力SCADA和工业控制等领域的人机交互界面常需要预定义一堆的行业标准 ...

  6. xmlplus 组件设计系列之十 - 网格(DataGrid)

    这一章我们要实现是一个网格组件,该组件除了最基本的数据展示功能外,还提供排序以及数据过滤功能. 数据源 为了测试我们即将编写好网格组件,我们采用如下格式的数据源.此数据源包含两部分的内容,分别是表头数 ...

  7. 把握linux内核设计思想(十二):内存管理之slab分配器

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流.请勿用于商业用途] 上一节最后说到对于小内存区的请求,假设採用伙伴系统来进行分配,则会在页内产生非 ...

  8. (转载)JavaWeb学习总结(五十二)——使用JavaMail创建邮件和发送邮件

    博客源地址:http://www.cnblogs.com/xdp-gacl/p/4216311.html 一.RFC882文档简单说明 RFC882文档规定了如何编写一封简单的邮件(纯文本邮件),一封 ...

  9. Kafka设计解析(十二)Kafka 如何读取offset topic内容 (__consumer_offsets)

    转载自 huxihx,原文链接 Kafka 如何读取offset topic内容 (__consumer_offsets) 众所周知,由于Zookeeper并不适合大批量的频繁写入操作,新版Kafka ...

  10. WCF入门(十二)---WCF异常处理

    WCF服务开发者可能会遇到需要以适当的方式向客户端报告一些不可预见的错误.这样的错误,称为异常,通常是通过使用try/catch块来处理,但同样,这是非常具体的技术. 由于客户端的关注领域不是关于如何 ...

随机推荐

  1. September 11th 2017 Week 37th Monday

    I believe there is a hero in all of us. 我相信每个人心中都住着一个英雄. For every of us, there are two version with ...

  2. scala数据库工具类

    scala的数据库连接池,基于mysql import java.util.concurrent.ConcurrentHashMap import com.jolbox.bonecp.{ BoneCP ...

  3. 更改Request Parameters中的值

    1. 定义ParameterRequestWrapper 继承HttpServletRequestWrapper public class ParameterRequestWrapper extend ...

  4. Echarts 曲线数少于图例数解决方法

    在上一篇文章 Echarts 多曲线“断点”问题解决方法 中说到了Angular 项目中要使用 Echarts 的方法. 说明了自己解决当“每一条曲线的横坐标不相同”时,在各条曲线上,它们的值采用数组 ...

  5. java内存分配策略

    对象的内存分配,从大方向将就是在堆上分配,对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓存,将按线程优先在TLAB上分配. 1. 对象优先在Eden区分配:大多数情况下,对象在新生代Ed ...

  6. 4-1 R语言函数 lapply

    #lapply函数 #可以循环处理列表中的每一个元素 #lapply(参数):lapply(列表,函数/函数名,其他参数) #总是返回一个列表 #sapply:简化结果 #结果列表元素长度均为1,返回 ...

  7. JWinner:一个私人定制的快速开发框架,为理想而生

    关于JWinner JWinner是一个JAVA项目的快速开发框架,他已经实现了大多数项目开发之前需要进行的一些必备工作,还有很多在开发过程中可能会用到的工具集. JWinner的诞生并不是一蹴而就的 ...

  8. SDWC补题计划

    2018的寒假去了SD的冬令营,因为一班二班难度悬殊,对我很不友好,几乎什么也没学会,但是我把两个班的课件都存了下来,现在慢慢把两个班的例题以及课后题都补一补(毕竟冬令营的钱不能白花). 这些题目横跨 ...

  9. 1088. [SCOI2005]扫雷Mine【网格DP】

    Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了 ,“余”人国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子 ...

  10. [JSOI2016]扭动的回文串

    题目 非常板子了 看到求什么最长的回文,我们就想到枚举回文中心的方法 首先对于这个回文串只包含在一个串内的情况,我们随便一搞就可以了,大概\(Manacher\)一下就没有了 对于那种扭动的回文串,我 ...