使用 CUnknown
[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 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宏包含在類別定義的 public 區段中。
類別建構函式
您的類別建構函式應該叫用父類別的建構函式方法,除了它對類別執行的任何動作之外。 下列範例是典型的建構函式方法:
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。
相關主題