长时间进行Windows编程的人一定对HRESULT特别熟悉,因为HRESULT作为一种函数的返回值类型曝光率实在太高了,可是你是否知道HRESULT到底是什么?为什么不直接使用简洁又亲切的BOOL作为函数的返回值类型呢?
单从名字上看,HRESULT似乎是指向函数结果的句柄,但是这种直观地猜想却是错误的。其实HRESULT的意义非常简单,它不是Handle to Result而是Here’s the Result。怎么样?H竟然是Here的缩写,相当与众不同吧!
为了对HRESULT一探究竟,我们可以打开WinError.h文件,看一看它对HRESULT的描述:HRESULT是COM函数/方法的返回值类型,它并非指向什么东西的句柄,而仅仅是一个32位的数值。HRESULT的32位被划分成多个区域,其结构如下所示:(博主对它进行了简化)
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 98 7 6 5 4 3 2 1 0
+-+-----------------------------+-------------------------------+
|S| Facility | Status |
+-+-----------------------------+-------------------------------+
HRESULT被划分成三个区域:紧急程度(S: 1 bit)、设备编号(Facility Code: 15 bit)和状态编号(Status Code: 16 bit)。这样一来你会发现,仅需1个bit(即S)就可以表示函数调用成功与否,余下的比特可以发挥更大的作用,它们携带的信息远比一个BOOL变量多得多,它们可以详细地说明函数调用过程中的各种情况,而不仅仅标明函数调用成功或失败。
观察HRESULT的结构之后,很容易明白下面这条规则:判断函数调用成功与否不能简单地将返回值与S_OK或E_NOINTERFACE等进行比较,而是要使用FAILED/SUCCEEDED宏。在WinError.h文件中,FAILED/SUCCEEDED宏的定义如下所示:
- <span style="font-family: Times New Roman; font-size: 18px;">#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
- #define FAILED(hr) (((HRESULT)(hr)) < 0)
- </span>
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#define FAILED(hr) (((HRESULT)(hr)) < 0)
当然,你知道FAILED/SUCCEEDED宏的秘密后,也可以直接在程序中将hr与0进行大小判断。不过为了使得代码规范化,建议你仍然使用预定义宏FAILED/SUCCEEDED,而且他们并不会降低程序的效率。
光是会“读”HRESULT是不够的,有的时候我们还要能够主动创建它,从而使得我们定义的函数也能返回HRESULT类型的值。这可以通过使用预定义宏MAKE_HRESULT来实现,它在WinError.h文件的定义如下所示:
- <span style="font-family: Times New Roman; font-size: 18px;">#defineMAKE_HRESULT(sev,fac,code) \
-
- ((HRESULT) (((unsigned long)(sev)<<31) | ((unsignedlong)(fac)<<16) | ((unsigned long)(code))))
- </span>
#defineMAKE_HRESULT(sev,fac,code) \
((HRESULT) (((unsigned long)(sev)<<31) | ((unsignedlong)(fac)<<16) | ((unsigned long)(code))))
在WinError.h文件中定义了很多错误码,能不能把函数的HRESULT类型返回值翻译成友好的错误提示呢?当然是可以的,我们可以通过调用Win32 API函数FormatMessage轻松实现,它的语法如下:
- <span style="font-family: Times New Roman; font-size: 18px;">DWORDWINAPI FormatMessage(
-
- __in DWORD dwFlags,
-
- __in_opt LPCVOID lpSource,
-
- __in DWORD dwMessageId,
-
- __in DWORD dwLanguageId,
-
- __out LPTSTR lpBuffer,
-
- __in DWORD nSize,
-
- __in_opt va_list* Arguments
-
- ); </span><span style="font-size: 16px;">
- </span>
DWORDWINAPI FormatMessage(
__in DWORD dwFlags,
__in_opt LPCVOID lpSource,
__in DWORD dwMessageId,
__in DWORD dwLanguageId,
__out LPTSTR lpBuffer,
__in DWORD nSize,
__in_opt va_list* Arguments
);
第1个参数dwFlags是格式化选项,如FORMAT_MESSAGE_ALLOCATE_BUFFER表示要为lpBuffer分配内存空间、FORMAT_MESSAGE_FROM_SYSTEM表示在系统消息定义表中查询错误码的意义;第2个参数lpSource表示临时的消息定义表,如果第1个参数包含FORMAT_MESSAGE_FROM_SYSTEM,lpSource就不起作用;第3个参数dwMessageId也就是错误码,传入LRESULT类型的数值;第4个参数dwLanguageId即语言标识符,它由两部分组成Primary Language(语言类型)和Sublanguage(国家或地区),用宏MAKELANGID构造;第5个参数lpBuffer是输出的消息,也即错误码的翻译结果;第6个参数nSize表示为lpBuffer最少分配的字节数;第7个参数可选,一般不使用。举一个应用的例子,如下所示:
- <span style="font-family: Times New Roman; font-size: 18px;">void*pMsgBuf;
-
- ::FormatMessage(
-
- FORMAT_MESSAGE_ALLOCATE_BUFFER| FROMAT_MESSAGE_FROM_SYSTEM,
-
- NULL,
-
- hr,
-
- MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
-
- (LPTSTR)&pMsgBuf,
-
- 0,
-
- NULL);
- </span>
void*pMsgBuf;
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER| FROMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&pMsgBuf,
0,
NULL);
读者不妨对应着上面的参数说明试着解释一下本例中各个实参的意义,更多细节可以参考MSDN的相关内容。
分享到:
相关推荐
标题中的“HRESULT错误检查简化器”是一个专门针对HRESULT值进行错误检查的工具或技术,它旨在简化在C++编程中处理HRESULT返回值的过程。HRESULT是Windows API和其他COM接口广泛使用的错误代码类型,用来报告操作...
在Windows编程中,错误处理是至关重要的,而`HRESULT`和`Windows Error Codes`是两种常见的错误处理机制。本文将深入解析它们之间的区别...理解并正确使用这两种错误处理机制,对于编写健壮的Windows应用程序至关重要。
通常,这样的文本文件会包含关键的代码片段、错误信息、调试步骤等,有助于读者理解问题的本质和解决方法。 在VBS编程中,常见问题可能包括语法错误、类型不匹配、权限问题、对象引用错误等。解决这些问题通常需要...
COM编程入门是一个面向初学者的主题,旨在帮助程序员理解并开始使用Component Object Model(COM)这一核心技术。COM是微软开发的一种二进制接口标准,它允许不同应用程序之间共享和交互对象,不受特定编程语言的...
COM 编程入门精讲是为刚刚接触 COM 的程序员提供编程指南,帮助他们理解 COM 的基本概念。COM 即组件对象模型,是 Component Object Model 取前三个字母的缩写,这三个字母在当今 Windows 的世界中随处可见。 COM ...
7. **错误处理**: COM使用 HRESULT 值作为返回码,通过HRESULT可以判断调用是否成功,以及失败的原因。 8. **激活服务**: COM提供激活服务,如本地服务器、In-Process Server(DLL)和Out-of-Process Server(EXE)...
CDHtmlDialog是MFC(Microsoft Foundation Classes)库中的一个类,它允许开发者在对话框中嵌入HTML页面,从而实现更加丰富和...理解并熟练运用这些交互技巧,能够帮助开发者创建出更加灵活、用户体验更好的应用程序。
程序员需要学会如何正确处理HRESULT,以判断操作是否成功,并根据返回的错误代码进行相应的错误处理。 通过COM技术,开发者可以利用Windows操作系统内置的组件和第三方提供的COM对象,如Windows外壳组件Shell。ATL...
这个工具对于开发者来说是学习和理解如何与Web服务交互的一个重要参考。通过WsdlReader,程序员可以自动化处理生成代理类的过程,而无需手动编写繁琐的代码,从而提高开发效率。 在C#中,Web Service是一种基于SOAP...
在使用这些产品时,如果遇到问题,系统会生成一个特定的错误代码,如“0x80070005”、“HRESULT 0x80040154”等,这些代码由字母、数字和符号组成,看起来可能复杂且难以理解,但实际上它们包含了丰富的信息。...
### VCADO数据库开发知识点概述 #### 一、导入ADO库 ...此外,随着技术的发展,现代的应用开发可能会更多地采用.NET Framework或C#等新技术栈来进行数据库开发,但理解传统的VC+ADO技术仍然是非常重要的基础。
HRESULT (__stdcall *QueryInterface)(void* this_ptr, REFIID riid, void** ppvObject); ULONG (__stdcall *AddRef)(void* this_ptr); ULONG (__stdcall *Release)(void* this_ptr); HRESULT (__stdcall *...
- `HRESULT GetName(BSTR *pName)`:获取组件名称,默认为“SimpleCOM”,如果设置了名称,则返回设置的名称。 - `HRESULT Add(double dLeftValue, double dRightValue, double *dRetVal)`:执行加法运算。 - `...
通过学习这些内容,开发者可以更好地理解和应用COM技术,构建出高效、可靠的应用程序。 ### 结论 COM作为一种强大的组件技术,在Windows平台上有着广泛的应用。了解其基本原理和技术细节对于Windows开发者来说至关...
结合标签"OPC Server Tool",我们可以理解这是一个专为OPC服务器设计的工具,不仅提供基本的配置功能,可能还具备高级特性,如数据记录、报警管理、安全性设置等。使用这类工具,工程师可以更高效地设置OPC服务器,...
首先,我们要理解 Delphi 是一个基于 Pascal 语言的集成开发环境(IDE),它提供了丰富的类库和组件,使得文件操作变得相对简单。在 Delphi 中,我们通常会使用 TFile 和 TDirectory 类来处理文件和目录的相关操作。...
在Windows操作系统中,通用串行通信(Serial Communication)是一种常用的数据传输方式...此外,还可以结合MSDN文档和其他资源,深入理解COM组件的工作原理和Windows串口通信的API使用方法,以提高编程效率和代码质量。
一个进程在其生命周期内可能会经历不同的状态变化,这些状态变化对于理解和设计高效的操作系统至关重要。 #### 二、进程状态 在典型的操作系统中,进程可能处于以下几种状态: 1. **就绪状态(Ready)**:进程...
这个“COM开发文档总汇”应该包含了从基础到高级的各个层面,可以帮助开发者深入理解COM机制,提高软件的复用性和可维护性。通过阅读文档中的例子和指南,你可以更好地运用COM技术在实际工作中解决问题。