使用 CUnknown
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
DirectShow 在名为 CUnknown 的 基类中实现 IUnknown。 可以使用 CUnknown 派生其他类,仅重写跨组件更改的方法。 DirectShow 中的大多数其他基类都派生自 CUnknown,因此组件可以直接从 CUnknown 继承,也可以从其他基类继承。
INonDelegatingUnknown
CUnknown 实现 INonDelegatingUnknown。 它在内部管理引用计数,在大多数情况下,派生类可以继承两个引用计数方法,而无需更改。 请注意,当引用计数降至零时 ,CUnknown 会删除自身。 另一方面,必须重写 CUnknown::NonDelegatingQueryInterface,因为基类中的 方法如果收到除 IID_IUnknown 以外的任何 IID,则返回E_NOINTERFACE。 在派生类中,测试支持的接口的 IID,如以下示例所示:
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_ISomeInterface)
{
return GetInterface((ISomeInterface*)this, ppv);
}
// Default: Call parent class method.
// The CUnknown class must be in the inheritance chain.
return CParentClass::NonDelegatingQueryInterface(riid, ppv);
}
实用工具函数 GetInterface (COM 帮助程序函数) 设置指针、以线程安全方式递增引用计数并返回S_OK。 在默认情况下,调用基类方法并返回结果。 如果派生自其他基类,请改为调用其 NonDelegatingQueryInterface 方法。 这使你能够支持父类支持的所有接口。
IUnknown
如前所述, IUnknown 的委派版本对于每个组件都是相同的,因为它只不过是调用非委派版本的正确实例。 为方便起见,头文件 Combase.h 包含一个宏 DECLARE_IUNKNOWN,它将三个委托方法声明为内联方法。 它扩展为以下代码:
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {
return GetOwner()->QueryInterface(riid,ppv);
};
STDMETHODIMP_(ULONG) AddRef() {
return GetOwner()->AddRef();
};
STDMETHODIMP_(ULONG) Release() {
return GetOwner()->Release();
};
实用工具函数 CUnknown::GetOwner 检索指向拥有此组件的组件的 IUnknown 接口的指针。 对于聚合组件,所有者是外部组件。 否则,组件拥有自身。 在类定义的公共节中包含 DECLARE_IUNKNOWN 宏。
类构造函数
类构造函数应调用父类的构造函数方法,以及它执行的任何特定于类的操作。 以下示例是典型的构造函数方法:
CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown(tszName, pUnk, phr)
{
/* Other initializations */
};
方法采用以下参数,这些参数直接传递给 CUnknown 构造函数方法。
- tszName 指定组件的名称。
- pUnk 是指向聚合 IUnknown 的指针。
- pHr 是指向 HRESULT 值的指针,指示方法的成功或失败。
总结
以下示例演示支持 IUnknown 的派生类和名为 ISomeInterface 的假设接口:
class CMyComponent : public CUnknown, public ISomeInterface
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if( riid == IID_ISomeInterface )
{
return GetInterface((ISomeInterface*)this, ppv);
}
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown(tszName, pUnk, phr)
{
/* Other initializations */
};
// More declarations will be added later.
};
此示例演示了以下几点:
- CUnknown 类实现 IUnknown 接口。 新组件继承自 CUnknown 和组件支持的任何接口。 组件可以从继承自 CUnknown 的另一个基类派生。
- DECLARE_IUNKNOWN 宏将委派 IUnknown 方法声明为内联方法。
- CUnknown 类提供 INonDelegatingUnknown 的实现。
- 若要支持 IUnknown 以外的接口,派生类必须重写 NonDelegatingQueryInterface 方法,并测试新接口的 IID。
- 类构造函数调用 CUnknown 的构造函数方法。
编写筛选器的下一步是使应用程序能够创建新的组件实例。 这需要了解 DLL 及其与类工厂和类构造函数方法的关系。 有关详细信息,请参阅 如何创建 DirectShow 筛选器 DLL。
相关主题