COM学习(四)——COM中的数据类型
上一次说到,COM为了跨语言,有一套完整的规则,只要COM组件按照规则编写,而不同的语言也按照对应的规则调用,那么就可以实现不同语言间相互调用。但是根据那套规则,只能识别接口,并调用没有参数和返回类型的接口,毕竟不同语言里面的基本数据类型不同,可能在VC++中char * 就表示字符串,而在Java或者c#中string是一个对象,二者的内存结构不同,不能简单的进行内存数据类型的强制转化。为了实现数据的正常交互,COM中又定义了一组公共的数据类型。
HRESULT类型:
在COM中接口的返回值强制定义为该类型,用于表示当前执行的状态是完成或者是出错,这个类型一般在VC中使用,别的语言在调用时根据接口的这个值来确定接下来该如何进行。
HRESULT类型的定义如下:
typedef _Return_type_success_(return >= 0) long HRESULT;
其实它就是一个32位的整数,微软将这个整数分成几个部分,各个部分都有详细的含义,这个值的详细解释在对应的winerror.h中。
//
// Note: There is a slightly modified layout for HRESULT values below,
// after the heading "COM Error Codes".
//
// Search for "**** Available SYSTEM error codes ****" to find where to
// insert new error codes
//
// Values are 32 bit values laid out as follows:
//
// 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 9 8 7 6 5 4 3 2 1 0
// +-+-+-+-+-+---------------------+-------------------------------+
// |S|R|C|N|r| Facility | Code |
// +-+-+-+-+-+---------------------+-------------------------------+
//
// where
//
// S - Severity - indicates success/fail
//
// 0 - Success
// 1 - Fail (COERROR)
//
// R - reserved portion of the facility code, corresponds to NT's
// second severity bit.
//
// C - reserved portion of the facility code, corresponds to NT's
// C field.
//
// N - reserved portion of the facility code. Used to indicate a
// mapped NT status value.
//
// r - reserved portion of the facility code. Reserved for internal
// use. Used to indicate HRESULT values that are not status
// values, but are instead message ids for display strings.
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
根据上面的注释可以看到,以及我自己查阅相关资料,它里面总共有7个部分,各个部分代表的含义如下:
S - 严重性 - 表示成功或失败0 - 成功,1 - 失败
R - 设施代码的保留部分,对应于NT的第二严重性位。1 - 严重故障
C - 第三方。 此位指定值是第三方定义还是Microsoft定义的。0 - Microsoft-定义,1 - 第三方定义
N - 保留部分设施代码。 用于指示映射的NT状态值。
X - 保留部分设施代码。 保留供内部使用。 用于指示不是状态值的HRESULT值,而是用于显示字符串的消息标识。
Facility - 表示引发错误的系统服务. 示例Facility代码如下所示:
2 - 调度(COM调度)
3 - 存储 (OLE存储)
4 - ITF (COM/OLE 接口管理)
7 - (原始 Win32 错误代码)
8 - Windows
9 - SSPI
10 - 控制
11 - CERT (客户端或服务器认证)
...
Code - 设施的状态代码
其实这些没有必要知道的很详细,只需要知道里面常用的几个即可:
S_OK:成功
S_FALSE:失败
E_NOINTERFACE:没有接口,一般是由QueryInterface或者CoCreateInterface函数返回,当我们传入的ID不对它找不到对应的接口时返回该值
E_OUTOFMEMORY:当内存不足时返回该值。
一般在COM的调用者看来,有的时候只要最高位不为0就表示成功,这个时候可能会继续使用,所以在我们自己编写组件的时候要根据具体情况选择返回值,不要错误了就返回S_FALSE,其实我们看它的定义可以知道它是等于1的,最高位为0,仍然是成功的。如果返回S_FALSE可能会造成意想不到的错误,而且还难以调试。
BSTR
COM中规定了一种通用的字符串类型BSTR,查看BSTR的定义如下:
typedef /* [wire_marshal] */ OLECHAR *BSTR;
typedef WCHAR OLECHAR;
从上面的定义上不难看出BSTR其实就是一个WCHAR ,也就是一个指向宽字符的指针。COM中使用的是UNICODE字符串,在编写COM程序的时候经常涉及到CString、WCHAR、char等的相互转化,其实本质上就是多字节字符与宽字节字符之间的转化。我们平时在进行char 与WCHAR之间转化的函数像WideCharToMultiByte和MultiByteToWideChar,以及W2A和A2W等。
COM为了方便使用,另外也提供了一组转化函数_com_util::ConvertBSTRToString以及_com_util::ConvertStringToBSTR用在在char与BSTR之间进行转化。需要注意的是,这组函数返回的字符串是在堆上分配出来的,使用完后需要自己释放。
在BSTR类型中,定义了两个函数SysAllocString(),和SysFreeString()用来分配和释放一个BSTR的内存空间。
在这总结一下他们之间的相互转化:
char----->BSTR: _com_util::ConvertStringToBSTR
WCHAR---->BSTR:可以直接用 = 进行赋值,也可以使用SysAllocString
BSTR---->WCHAR:一般是直接使用等号即可,但是在WCHAR使用完之前不能释放,所以一般都是赋值给一个CString
BSTR---->char:_com_util::ConvertBSTRToString
Convert函数是定义在头文件atlutil.h中并且需要引用comsupp.lib文件
另外COM封装了一个_bstr_t的类,使用这个类就更加方便了,它封装了与char之间的相互转化,可以直接使用赋值符号进行相互转化,同时也不用考虑回收内存的问题,它自己会进行内存回收。
VARIANT 万能类型
现代编程语言一般有强类型的语言和弱类型的语言,强类型的像C/C++、Java这样的,必须在使用前定义变量类型,而弱类型像Python这样的可以直接定义变量而不用管它的类型,甚至可以写出像:
i = 0
i = "hello world"
这样的代码,而且不同语言中可能同一种类型的变量在内存布局上也可能不一样。解决不同语言之间变量类型的冲突,COM定义了一种万能类型——VARIANT。
typedef struct tagVARIANT VARIANT;
typedef struct tagVARIANT VARIANTARG;
struct tagVARIANT
{
union
{
struct __tagVARIANT
{
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union
{
LONGLONG llVal;
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
_VARIANT_BOOL bool;
SCODE scode;
CY cyVal;
DATE date;
BSTR bstrVal;
IUnknown *punkVal;
IDispatch *pdispVal;
SAFEARRAY *parray;
BYTE *pbVal;
SHORT *piVal;
LONG *plVal;
LONGLONG *pllVal;
FLOAT *pfltVal;
DOUBLE *pdblVal;
VARIANT_BOOL *pboolVal;
_VARIANT_BOOL *pbool;
SCODE *pscode;
CY *pcyVal;
DATE *pdate;
BSTR *pbstrVal;
IUnknown **ppunkVal;
IDispatch **ppdispVal;
SAFEARRAY **pparray;
VARIANT *pvarVal;
PVOID byref;
CHAR cVal;
USHORT uiVal;
ULONG ulVal;
ULONGLONG ullVal;
INT intVal;
UINT uintVal;
DECIMAL *pdecVal;
CHAR *pcVal;
USHORT *puiVal;
ULONG *pulVal;
ULONGLONG *pullVal;
INT *pintVal;
UINT *puintVal;
struct __tagBRECORD
{
PVOID pvRecord;
IRecordInfo *pRecInfo;
} __VARIANT_NAME_4;
} __VARIANT_NAME_3;
} __VARIANT_NAME_2;
DECIMAL decVal;
} __VARIANT_NAME_1;
};
从定义上看出,它其实是一个巨大的联合体,将所有C/C++的基本类型都包含进来,甚至包含了像BSTR, 这样的COM中使用的类型。它通过成员vt来表示它当前使用的是哪种类型的变量。vt的类型是一个枚举类型,详细的定义请参见MSDN。为了简化操作,COM中也对它进行了一个封装——_variant_t,该类型可以直接使用任何类型的数据对其进行初始化操作。但是在使用里面的值时还是得判断它的vt成员的值
COM中的其他操作
最后附上一张COM常用函数表以供参考:

COM学习(四)——COM中的数据类型的更多相关文章
- MySQL数据库学习四 存储引擎和数据类型
4.1存储引擎 1. 查看MySQL DBMS所支持的存储引擎 SHOW ENGINES;
- 【Python学习】Python中的数据类型精度问题
Python真的很神奇...神奇到没有直接的数据类型概念,并且精度可以是任意精度.想当初,第一次接触OI算法时,写得第一个算法就是高精度加法,捣鼓了半天.一切在Python看来,仅仅三行代码即可完成. ...
- python学习第九讲,python中的数据类型,字符串的使用与介绍
目录 python学习第九讲,python中的数据类型,字符串的使用与介绍 一丶字符串 1.字符串的定义 2.字符串的常见操作 3.字符串操作 len count index操作 4.判断空白字符,判 ...
- Javascript高级编程学习笔记(3)—— JS中的数据类型(1)
前一段时间由于事情比较多,所以笔记耽搁了一段时间,从这一篇开始我会尽快写完这个系列. 文章中有什么不足之处,还望各位大佬指出. JS中的数据类型 上一篇中我写了有关JS引入的Script标签相关的东西 ...
- python学习第八讲,python中的数据类型,列表,元祖,字典,之字典使用与介绍
目录 python学习第八讲,python中的数据类型,列表,元祖,字典,之字典使用与介绍.md 一丶字典 1.字典的定义 2.字典的使用. 3.字典的常用方法. python学习第八讲,python ...
- python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍
目录 python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍 一丶元祖 1.元祖简介 2.元祖变量的定义 3.元祖变量的常用操作. 4.元祖的遍历 5.元祖的应用场景 p ...
- python学习第六讲,python中的数据类型,列表,元祖,字典,之列表使用与介绍
目录 python学习第六讲,python中的数据类型,列表,元祖,字典,之列表使用与介绍. 二丶列表,其它语言称为数组 1.列表的定义,以及语法 2.列表的使用,以及常用方法. 3.列表的常用操作 ...
- js中判断数据类型的四种方法总结
js中判断数据类型的四种方法 前言 在js中,我们经常需要判断数据的类型,那么哪些方法可以用来判断数据的类型呢?哪种方法判断数据类型最准确呢? 我们来一个个分析: 1.typeof typeof是一个 ...
- 零基础学习java------day2------关键字、标志符、常量、进制键的转换、java中的数据类型、强制类型转换的格式
今日内容要求: 1. 了解关键字的概念及特点,了解保留字 2. 熟练掌握标识符的含义,特点,可使用字符及注意事项 3. 了解常量的概念,进制,进制之间相互转换,了解有符号标识法的运算方式 4. 掌握变 ...
- MySQL学习之路3-MySQL中常用数据类型
MySQL中常用数据类型 字符型 存储字符型数据.例如姓名,地址,电话号码等.使用引号括起来,一般使用单引号. 常用类型: char(255) 定长字符串,最大长度255个字符. varchar(25 ...
随机推荐
- Codeforces 29D Ant on the Tree 树的遍历 dfs序
题目链接:点击打开链接 题意: 给定n个节点的树 1为根 则此时叶子节点已经确定 最后一行给出叶子节点的顺序 目标: 遍历树并输出路径.要求遍历叶子节点时依照给定叶子节点的先后顺序訪问. 思路: 给每 ...
- Python笔记·第二章—— Python的编码问题(一)
一.什么是编码 可以说,计算机是一个即聪明又笨蛋的家伙.说它聪明,是因为他可以做很多事情,它的强大无需多说,大家应该都有所了解以及感受.但是为什么说它又是个笨蛋呢,因为我们在电脑上写出的每一个字,保存 ...
- 面试题(php部分)
1.用PHP打印出前一天的时间格式是2006-5-10 22:21:21(2分) [答案] $a = date("Y-m-d H:i:s", strtotime("-1 ...
- Linux chown
在学习 兄弟连 linux教学视频 的时候,我将所学的 linux 命令记录在我的博客中,方便自己查阅. 权限管理命令: chown 基础的命令 命令名称:chown 命令英文原意:change fi ...
- The ResourceConfig instance does not contain any root resource classes
问题描述 当我们在使用 myeclipse 创建 Web Service Projects 项目后,运行项目然后就会出现这个问题. 解决方案 通过这个错误描述,我们项目没有找到这个资源.报错的原因在于 ...
- 使用MyBatis缓存
(1).为什么需要使用缓存:: MyBatis是一个持久层(数据库层)映射框架,在所有访问数据库的操作中,无疑数据查询是最耗费数据库资源的操作了,因为你一次可能需要查询成千上百万条记录(如果你不加限制 ...
- 使用MVC创建API
1.新建MVC-WebAPI 2.Build后页面是这样的,这就是我们需要的页面. 3.自己Add API的页面,然后Run,会发现页面没有action和Description 4.显示action, ...
- Redis4.0.0 安装及配置 (Linux — Centos7)
本文中的两个配置文件可在这里找到 操作系统:Linux Linux发行版:Centos7 安装 下载地址,点这里Redis4.0.0.tar.gz 或者使用命令: wget http://downlo ...
- 54、js初识
今天这篇将介绍javascript,学完javascript就可以使你的网页动起来. 一.JavaScript概述 1.JavaScript的历史 1992年Nombas开发出C-minus-min ...
- 用Azure AD 实现Web 应用身份认证的Multi-Factor Authentication(MFA)
最近客户有个需求,希望把面向public的Web应用中的终端用户数据库由Azure AD来实现,同时希望可以用MFA来实现用户身份认证.这个想法非常好,通过使用Azure的managed servic ...