COM学习笔记

COM所有内容起于接口,终于接口。

定义COM接口,就是定义vtbl(虚拟函数表)结构。

COM规范对接口(vtbl结构)强制约定如下:

  1. 接口一旦公布,vtbl结构不应再变化;

  1. 接口在所有子孙级别上的所有派生类,以及每个派生类的所有实例,它们的vtbl结构必须和该接口定义的vtbl结构一致;

  1. 接口必须继承IUnknown,使vtbl结构的前三个函数固定为QueryInterface/AddRef/Release;

  1. 接口都不能以虚拟方式继承IUnknown(否则该接口的前三个函数指向的将不是IUnknown三函数)

IUnknown接口:

  1. 有且仅有三个成员函数QueryInterface/AddRef/Release

  1. 不是虚拟基类,也不应被虚拟继承。

Win32 SDK的UNKNWN.H头文件直接支持了IUnknown接口,其定义如下:

interface IUnknown
{
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) = 0;
    virtual ULONG __stdcall AddRef() = 0;
    virtual ULONG __stdcall Release() = 0;
}

其他平台或函数库,也许未对IUnknown直接支持,此时需要程序员自行定义。

COM接口最自然的实践,就是在Windows平台利用C++的纯抽象基类进行实现。

客户和组件越“不熟”越好。

CreateInstance可建立组件并返回其IUnknown指针

QueryInterface的Win32 C++原型

HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)

意义
注意事项

参数1

标识所查询的接口,IID指“接口标识符”(Interface ID)

组件支持的IID应事先与COM组件一起公开发布(如存放在头文件或类型库中)

参数2

查询到的接口指针地址

查询不到接口时应为空

返回值

具有特定结构的32位值(并非handle句柄)

须用SUCCEEDED和FAILED两个宏判断,避免直接与S_OK或E_NOINTERFACE比较。

QueryInterface满足对称传递自反三大特性,具体规则如下:

实现 QueryInterface 的规则 - Win32 apps | Microsoft Learn

从集合论与图论的角度看问题,可将接口看作满足关系QueryInterface的闭包,并把组件看成是多个这种闭包相连的图。由于关系QueryInterface即是对称的又是传递的还是自反的,那么每个闭包之间都可以直接相连。

这个结论从COM对象的角度来描述就是,对象的任意一个接口,对于同样的QueryInterface请求,回答都应该是相同的。

三大特性也意味着COM对象必须满足:

  1. 对象必须具有唯一标识

  1. 对象的接口集必须是静态的(不随时间变化)

实现层面,往往使用一个类实现组件提供的多个接口,此时会产生多重继承关系如下:

interface IX : IUnknown {/*...*/};
interface IY : IUnknown {/*...*/};
class CA : public IX, public IY {/*...*/};

注意到IX和IY都是继承自IUnknown,也就意味着CA同时继承了两个IUnknown接口(一个来自IX,一个来自IY),将CA强制转换成IUnknown接口时会报错:

// 这句话会报错
*ppv = static_case<IUnknown*>(this);

所以当QueryInterface收到IID_IUnknown查询时,必须返回确定的派生对象:

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
    // 其他代码...
    if (iid == IID_IUnknown)
    {
        // 这里一般返回和基类更接近的派生类对象
        *ppv = static_case<IX*>(this);
    }
    // 其他代码...
}

(未完待续)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值