2.1 再谈接口与实现
其实从上一章“COM是个更好的C++”可以看出,COM最重要的就是将接口与实现分离。
上一章中接口定义头文件中采用C++抽象类的形式,如果调用方是C++环境当然不会有问题。但如果调用方不是C++的编译环境呢?
为了把“接口定义”与“特定实现过程所用到的语言”之间的关联尽可能的断开,我们必须把这两项分离开来,如果所有参与的各方统一使用一种语言(而非C++抽象基类)来定义接口,那么就有可能只定义一次接口,然后在必要的时候导出新的、与实现语言相关的接口定义来。COM提供了这样一种语言,只用到基本的、大家熟悉的C语法,同时加入某些用来“消除C语言二义性特征”的能力。这种语言被称为接口定义语言(Interface Definition Language, IDL)
2.2 IDL
IDL语法就是简单的C语法。IDL支持struct,union,enum,typedef。
IDL属性位于方括号中,多个属性之间以逗号作为分割符,即所谓的属性列表,以区别于基本的IDL文本流。属性总是出现在相应主题的定义之前。
[
v1_enum,helpstring("This is a color!")
]
enum COLOR {
RED, GREEN, BLUE}
当我们在IDL中定义COM方法时,我们必须要显式地指明调用方或被调用方将写入或读每一个参数。
void Method1([in] long arg1,
[out] long *parg2,
[in,out] long *parg3);
2.3 方法和结果
几乎所有的COM方法都会返回一个HRESULT类型的错误号。对于许多COM兼容的实现语言(如VB,JAVA),这些HRESULT被运行时库或虚拟机截取,然后被映射成为语言中特定的异常(exception)
HRESULT是32位的整数。包含比如网络错误、服务器失败等信息
//31位:严重程度位
//30-29位:保留
//28-16位:操作码
//15-0位:信息码
#define SUCCEEDED(hr) (long(hr) >= 0)
#define FAILED(hr) (long(ht) < 0)
//这两个宏充分利用了“当把HRESULT当作有符号的整数时,严重程序位也就是符号位”这一事实
S_OK 一般操作,成功执行
S_FALSE 成功地返回逻辑错误
E_FAIL 一般性失败
E_NOTIMPL 方法没有实现
E_UNEXPECTED 在不准确的时间调用了方法
为了让方法返回一个与“方法的物理HRESULT”不相关的逻辑结果,COM IDL支持retval参数属性,表示: * 相关的物理方法参数 实现上是 操作的逻辑结果 * ,在支持retval的环境中,该参数应该被映射为操作的结果。
HRESULT Method2([in] short arg1,
[out,retval] short* arg2);
在Java语言中,被映射为下面的函数:
public short Method2(