IUnknown 的工作原理
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
IUnknown 中的方法使应用程序能够查询组件上的接口并管理组件的引用计数。
引用计数
引用计数是一个内部变量,在 AddRef 方法中递增,在 Release 方法中递减。 基类管理引用计数,并在多个线程之间同步对引用计数的访问。
接口查询
查询接口也很简单。 调用方传递两个参数:接口标识符 (IID) ,以及指针的地址。 如果组件支持请求的接口,它将设置指向接口的指针,递增其自己的引用计数,并返回S_OK。 否则,它将指针设置为 NULL 并返回E_NOINTERFACE。 以下伪代码显示了 QueryInterface 方法的一般概述。 下一部分所述的组件聚合引入了一些额外的复杂性。
if (IID == IID_IUnknown)
set pointer to (IUnknown *)this
AddRef
return S_OK
else if (IID == IID_ISomeInterface)
set pointer to (ISomeInterface *)this
AddRef
return S_OK
else if ...
else
set pointer to NULL
return E_NOINTERFACE
一个组件的 QueryInterface 方法与另一个组件的 QueryInterface 方法之间的唯一区别是每个组件测试的 IID 列表。 对于组件支持的每个接口,组件必须测试该接口的 IID。
聚合和委派
组件聚合必须对调用方透明。 因此,聚合必须公开单个 IUnknown 接口,聚合组件将延迟到外部组件的实现。 否则,调用方将在同一聚合中看到两个不同的 IUnknown 接口。 如果未聚合组件,它将使用其自己的实现。
若要支持此行为,组件必须添加间接级别。 委派 IUnknown 将工作委托到适当的位置:外部组件(如果有)或组件的内部版本。 未交付的 IUnknown 执行工作,如上一部分所述。
委派版本是公共版本,并保留名称 IUnknown。 非交付版本重命名为 INonDelegatingUnknown。 此名称不是 COM 规范的一部分,因为它不是公共接口。
当客户端创建组件的实例时,它会调用 IClassFactory::CreateInstance 方法。 一个参数是指向聚合组件的 IUnknown 接口的指针,如果未聚合新实例,则为 NULL 。 组件使用此参数来存储一个成员变量,该变量指示要使用的 IUnknown 接口,如以下示例所示:
CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
if (pOuterUnknown == NULL)
m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
else
m_pUnknown = pOuterUnknown;
[ ... more constructor code ... ]
}
委托 IUnknown 中的每个方法都会调用其非委托对应方法,如以下示例所示:
HRESULT QueryInterface(REFIID iid, void **ppv)
{
return m_pUnknown->QueryInterface(iid, ppv);
}
根据委托的性质,委托方法在每个组件中看起来都是相同的。 只有未交付的版本会更改。
相关主题