手順 6. COM サポートの追加
最後に、COM のサポートを追加する。
参照カウント
AddRef や Release を実装する必要はない。すべてのフィルタとピン クラスは、参照カウントを処理する CUnknown から派生する。
QueryInterface
すべてのフィルタとピン クラスは、継承する COM インターフェイスに対する QueryInterface を実装する。たとえば、CTransformFilter は IBaseFilter を継承する (CBaseFilter を介する)。フィルタがさらにインターフェイスを公開しない場合は、他に何もする必要はない。
追加インターフェイスを公開する場合は、CUnknown::NonDelegatingQueryInterface メソッドをオーバーライドする。たとえば、フィルタは IMyCustomInterface というカスタム インターフェイスを実装すると想定する。このインターフェイスをクライアントに公開するには、次の処理を行う。
- そのインターフェイスからフィルタ クラスを派生する。
- パブリック宣言セクションに DECLARE_IUNKNOWN マクロを指定する。
- インターフェイスの IID を調べ、フィルタへのポインタを返すように NonDelegatingQueryInterface をオーバーライドする。
次のコードにこれらの手順を示す。
CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
if (riid == IID_IMyCustomInterface) {
return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}
詳細については、「IUnknown の実装方法」を参照すること。
オブジェクト作成
フィルタを DLL にパッケージ化し、他のクライアントが利用できるようにする場合、CoCreateInstance および他の関連 COM 関数をサポートする必要がある。大部分は基底クラス ライブラリが実装するため、自分のフィルタに関する情報を提供するだけでよい。ここでは、必要な処理を簡単に説明する。詳細については、「DLL の作成方法」を参照すること。
初めに、フィルタの新しいインスタンスを返す静的クラス メソッドを作成する。このメソッドには任意の名前を付けられるが、シグニチャは次の例に示すものに一致させる必要がある。
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
次に、g_Templates という名前の CFactoryTemplate クラスのグローバル配列を宣言する。各 CFactoryTemplate クラスには 1 つのフィルタ用のレジストリ情報が含まれる。1 つの DLL に複数のフィルタを含められる。CFactoryTemplate エントリを追加するだけでよい。また、プロパティ ページなど、他の COM オブジェクトも宣言できる。
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
値が g_Templates 配列の長さに等しい、g_cTemplates いうグローバル整数を定義する。
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
最後に、DLL 登録関数を実装する。次の例は、こうした関数の最小限の実装を示している。
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
フィルタ レジストリ エントリ
前の例は、COM に対するフィルタの CLSID を登録する方法を示している。多くのフィルタには、これで十分である。その場合、クライアントは CoCreateInstance を使ってフィルタを作成し、IFilterGraph::AddFilter を呼び出してフィルタ グラフに追加する。しかし、場合によっては、レジストリのフィルタに関する情報の追加が必要になることがある。この情報により、次のことが可能になる。
- クライアントはフィルタ マッパーまたは System Device Enumerator を使ってフィルタを発見できる。
- フィルタ グラフ マネージャは自動グラフ作成中にフィルタを発見できる。
次の例では、ビデオ圧縮カテゴリに RLE エンコーダ フィルタを登録する。詳細については、「DirectShow フィルタの登録方法」を参照すること。特に、「フィルタ登録のガイドライン」を読むこと。フィルタ登録で推奨する処理について説明している。
// メディア タイプ情報を宣言する。
FOURCCMap fccMap = FCC('MRLE');
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };
// ピン情報を宣言する。
REGFILTERPINS sudPinReg[] = {
// 入力ピン。
{ 0, FALSE, // Rendered?
FALSE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudInputTypes // Media types.
},
// 出力ピン。
{ 0, FALSE, // レンダリングされているか?
TRUE, // 出力?
FALSE, // ゼロ?
FALSE, // 複数?
0, 0,
1, &sudOutputTypes // メディア タイプ。
}
};
// フィルタ情報を宣言する。
REGFILTER2 rf2FilterReg = {
1, // バージョン番号。
MERIT_DO_NOT_USE, // メリット。
2, // ピンの数。
sudPinReg // ピン情報へのポインタ。
};
STDAPI DllRegisterServer(void)
{
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_RLEFilter, // フィルタ CLSID。
g_wszName, // フィルタ名。
NULL, // デバイス モニカ。
&CLSID_VideoCompressorCategory, // ビデオ コンプレッサ カテゴリ。
g_wszName, // インスタンス データ。
&rf2FilterReg // フィルタ情報。
);
pFM2->Release();
}
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_RLEFilter);
pFM2->Release();
}
return hr;
}
また、フィルタも DLL 内でパッケージ化する必要はない。場合によっては、特定のアプリケーションだけのために設計された専用フィルタを作成できる。その場合、フィルタ クラスを直接アプリケーションでコンパイルし、次の例に示すように、new 演算子を使って作成できる。
#include "MyFilter.h" // フィルタ クラスを宣言するヘッダー ファイル。
// MyFilter.cpp をコンパイルし、リンクする。
int main()
{
IBaseFilter *pFilter = 0;
{
// pF を非表示にする範囲。
CMyFilter* pF = new MyFilter();
if (!pF)
{
printf("Could not create MyFilter.\n");
return 1;
}
pF->QueryInterface(IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));
}
/* ここでは通常どおり pFilter を使う。 */
pFilter->Release(); // フィルタを削除する。
return 0;
}
参照