使用 CUnknown

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 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.
};

此示例演示了以下几点:

编写筛选器的下一步是使应用程序能够创建新的组件实例。 这需要了解 DLL 及其与类工厂和类构造函数方法的关系。 有关详细信息,请参阅 如何创建 DirectShow 筛选器 DLL

如何实现 IUnknown