【转载】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 中,选中组件支持错误处理接口
七、小结
阅读文章后,请下载本回的示例程序。示例程序中演示了三种错误处理方法和三种接收错误的方法,同时程序中也有比较详细的注释。
【转载】COM 组件设计与应用(十二)——错误与异常处理的更多相关文章
- AngularJs的UI组件ui-Bootstrap分享(十二)——Rating
Rating是一个用于打分或排名的控件.看一个最简单的例子: <!DOCTYPE html> <html ng-app="ui.bootstrap.demo" x ...
- 2017-2018-1 《Linux内核原理与设计》第十二周作业
<linux内核原理与设计>第十二周作业 Sql注入基础原理介绍 分组: 和20179215袁琳完成实验 一.实验说明 SQL注入攻击通过构建特殊的输入作为参数传入Web应用程序,而这 ...
- 【转载】COM 组件设计与应用(二)——GUID 和 接口
原文:http://vckbase.com/index.php/wv/1203.html COM 组件设计与应用 系列文章:http://vckbase.com/index.php/piwz?& ...
- Bootstrap组件福利篇:十二款好用的组件推荐
阅读目录 一.时间组件 1.效果展示 2.源码说明 3.代码示例 二.自增器组件 1.效果展示 2.源码说明 3.代码示例 三.加载效果 一.实用型 二.炫酷型 四.流程图小插件 1.效果展示 2.源 ...
- HT图形组件设计之道(二)
上一篇我们自定义CPU和内存的展示界面效果,这篇我们将继续采用HT完成一个新任务:实现一个能进行展开和合并切换动作的刀闸控件.对于电力SCADA和工业控制等领域的人机交互界面常需要预定义一堆的行业标准 ...
- xmlplus 组件设计系列之十 - 网格(DataGrid)
这一章我们要实现是一个网格组件,该组件除了最基本的数据展示功能外,还提供排序以及数据过滤功能. 数据源 为了测试我们即将编写好网格组件,我们采用如下格式的数据源.此数据源包含两部分的内容,分别是表头数 ...
- 把握linux内核设计思想(十二):内存管理之slab分配器
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流.请勿用于商业用途] 上一节最后说到对于小内存区的请求,假设採用伙伴系统来进行分配,则会在页内产生非 ...
- (转载)JavaWeb学习总结(五十二)——使用JavaMail创建邮件和发送邮件
博客源地址:http://www.cnblogs.com/xdp-gacl/p/4216311.html 一.RFC882文档简单说明 RFC882文档规定了如何编写一封简单的邮件(纯文本邮件),一封 ...
- Kafka设计解析(十二)Kafka 如何读取offset topic内容 (__consumer_offsets)
转载自 huxihx,原文链接 Kafka 如何读取offset topic内容 (__consumer_offsets) 众所周知,由于Zookeeper并不适合大批量的频繁写入操作,新版Kafka ...
- WCF入门(十二)---WCF异常处理
WCF服务开发者可能会遇到需要以适当的方式向客户端报告一些不可预见的错误.这样的错误,称为异常,通常是通过使用try/catch块来处理,但同样,这是非常具体的技术. 由于客户端的关注领域不是关于如何 ...
随机推荐
- Python基础第一篇-------python的介绍
一.python的介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本 ...
- [翻译] RSKImageCropper
RSKImageCropper https://github.com/ruslanskorb/RSKImageCropper An image cropper for iOS like in the ...
- Linux查看系统当前字符集
常用的命令展示 参考当前环境的字符集 方法一: cat /etc/sysconfig/i18n [ssh客户端工具最好也是utf-8,保持一致] 方法二:echo $LANG 设置当前环境的字符集 方 ...
- git五分钟教程
使用Git前,需要先建立一个仓库(repository).您可以使用一个已经存在的目录作为Git仓库或创建一个空目录. 使用您当前目录作为Git仓库,我们只需使它初始化. git init 使用我们指 ...
- SpringMVC如何防御CSRF
本文说一下SpringMVC如何防御CSRF(Cross-site request forgery跨站请求伪造)和XSS(Cross site script跨站脚本攻击). 说说CSRF 对CSRF来 ...
- spring中MessageSource的配置使用方法3--ResourceBundleMessageSource【转】
本文转载仅供自己学习收录,不做任何商业用途,如有需要请访问原地址:http://blog.csdn.net/qyf_5445/article/details/8124431 ApplicationCo ...
- win8中常见问题排查
1. 无法使用内置管理员账户打开 1.1 启动组策略编辑器:运行中“gpedit.msc”,1.2 依次展开“计算机配置”--->“Windows设置”--->“安全设置”--->“ ...
- Oracle-本地连接没问题,远程连接有问题解决方式
1. 问题 我的环境是oracle11gr2,本地用plsql还是toad连接都没有不论什么问题,而用别的机器远程连接就提示 无监听程序等错误. 2. 原因 oracle安装路径 --- 比如: F ...
- P2607 [ZJOI2008]骑士
题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里, ...
- Vue2+Webpack创建vue项目
相比较AngularJS和ReactJS,VueJS一直以轻量级,易上手称道.MVVM的开发模式也使前端从原先的DOM中解放出来,我们在不需要在维护视图和数据的统一上花大量时间,只需要关注于data的 ...