Date

GraphEdit を使うとフィルタ独自のプロパティページを表示することができる。ここで作ったフィルタ にプロパティページを追加して GraphEdit から表示できるようにしてみよう。

プロパティページの準備

プロパティページはCBasePropertyPageを派生した COM クラスとして定義する。GUID を定義し、regsvr32 で登録できるようにする必要がある。ここではプロパティページのクラスをCMySourceExPropとして定義する。

まずCMySourceExPropのクラスIDを定義する。

1
2
3
// {3248D86E-4450-4f2b-AD43-5D8DDCFBABB6}
DEFINE_GUID(CLSID_MySourceExProp,
0x3248d86e, 0x4450, 0x4f2b, 0xad, 0x43, 0x5d, 0x8d, 0xdc, 0xfb, 0xab, 0xb6);

CMySourceExProp を regsvr32 で登録するために g_Templatesを拡張する。

1
2
3
4
CFactoryTemplate g_Templates [] = {
     { TEMPLATE_NAME,      &CLSID_MySourceEx,     CMySourceEx::CreateInstance, NULL, &afFilterInfo },
     { PROP_TEMPLATE_NAME, &CLSID_MySourceExProp, CMySourceExProp::CreateInstance, NULL, NULL}
};

IDD_PROPというリソース ID でプロパティページのリソースを作成する。

IDS_PROP_TITLEというリソース ID で文字列リソースを作成する。プロパティページのタブに表示される文字列として使われる。

ソースフィルタクラスの拡張

ソースフィルタクラスCMySourceExにcode>ISpecifyPropertyPagesインターフェイスを実装する。NonDelegatingQueryInterface`も問い合わせに対応できるように修正しよう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class CMySourceEx : CSource, public IColor, public ISpecifyPropertyPages {
public:
    DECLARE_IUNKNOWN
    CMySourceEx(LPUNKNOWN pUnk,HRESULT *phr);
    ~CMySourceEx();
    static CUnknown * WINAPI    CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
    //IColor
    STDMETHODIMP SetColor(DWORD color);
    STDMETHODIMP GetColor(DWORD *pColor);
    //ISpecifyPropertyPages
    STDMETHODIMP GetPages(CAUUID *pPages);
protected:
private:
    DWORD m_Color;
};
1
2
3
4
5
6
STDMETHODIMP CMySourceEx::NonDelegatingQueryInterface(REFIID riid, void **ppv) {
    if (riid==IID_ISpecifyPropertyPages) {
        return GetInterface((ISpecifyPropertyPages*)this, ppv);
    }
    return CSource::NonDelegatingQueryInterface(riid, ppv);
}

GetPagesではプロパティページのクラスIDを引数のpPagesに設定する。CoTaskMemAllocでクラスIDを格納するメモリを動的確保すること。

1
2
3
4
5
6
7
8
STDMETHODIMP CMySourceEx::GetPages(CAUUID *pPages) {
    CheckPointer(pPages, E_POINTER);
    pPages->cElems=1;
    pPages->pElems=(GUID*)CoTaskMemAlloc(sizeof(GUID));
    CheckPointer(pPages->pElems, E_OUTOFMEMORY);
    pPages->pElems[0]=CLSID_MySourceExProp;
    return S_OK;
}

プロパティクラスの実装

プロパティクラスは DirectShow 基底クラスにある CBasePropertyPage クラスを派生させて作成する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class CMySourceExProp : CBasePropertyPage
{
public:
    CMySourceExProp(IUnknown *pUnknown);
    static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
    HRESULT OnConnect(IUnknown *pUnknown);
    HRESULT OnActivate(void);
    BOOL OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    HRESULT OnApplyChanges(void);
    HRESULT OnDisconnect(void);
private:
    IColor *m_pColor;
    DWORD   m_CurrVal;
    DWORD   m_NewVal;
};

m_CurrValm_NewVal に注目してほしい。プロパティページを開くと、OK, Apply, Cancel の 3 つのボタンが存在する。ユーザがスライダーを動かして明るさを変更したあと、Cancel ボタンを押下したとき、以前の明るさに戻してプロパティページが閉じられるのが自然であろう。従って「新しく設定する値(m_NewVal)」と「現在の値(m_CurrVal)」を保持しておく必要がある。

OnConnectでは、プロパティページが作成されたときに呼び出される。引数のIUnknownインターフェイスはフィルタへのポインタになっている。QueryInterfaceを使ってIColorインターフェイスを問い合わせておく。

1
2
3
4
5
HRESULT CMySourceExProp::OnConnect(IUnknown *pUnknown) {
    HRESULT hr=pUnknown->QueryInterface(
        __uuidof(IColor), (void**)&m_pColor);
    return hr;
}

OnActivateも同様にプロパティページが作成されたときに呼び出される。ここでのタスクはプロパティページのUIの初期化を行うことである。Icolor::GetColorを呼び出し現在値をm_CurrValに取得し UI を初期化する。

1
2
3
4
5
6
7
HRESULT CMySourceExProp::OnActivate(void) {
    InitCommonControls();
    m_pColor->GetColor(&m_CurrVal);
    SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETRANGE, 0,MAKELONG(0, 255));
    SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETPOS, 1, m_CurrVal);
    return S_OK;
}

OnReceiveMessageはメッセージプロシージャである。スライダーコントロールを操作するとメンバ変数 m_NewVal が更新される。IColor::SetColor を呼び出し、すぐに画面に反映されるようにしておく。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
BOOL CMySourceExProp::OnReceiveMessage
    (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_HSCROLL:
        switch(LOWORD(wParam)) {
        case TB_PAGEDOWN:
        case SB_THUMBTRACK:
        case TB_PAGEUP:
            m_NewVal=SendDlgItemMessage(m_Dlg, IDC_SLIDER1,
                TBM_GETPOS, 0, 0);
            m_pColor->SetColor(m_NewVal);
            __super::m_bDirty=TRUE;
            if(__super::m_pPageSite) {
                __super::m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
            }
        }
        return (LRESULT)1;
    }
    return CBasePropertyPage::OnReceiveMessage(hwnd,uMsg,wParam,lParam);
}

OnApplyChangesは Apply ボタンや OK ボタンが押下されたときに呼び出される。メンバ変数 m_CurrValm_NewVal を代入する。

1
2
3
4
HRESULT CMySourceExProp::OnApplyChanges(void) {
    m_CurrVal=m_NewVal;
    return S_OK;
}

OnDisconnectはプロパティページが閉じられるときに呼び出される。メンバ変数 m_CurrValIColor::SetColor を呼び出す。そして取得したインターフェイスを解放する。

もしユーザが Cancel ボタンを押下した場合、OnApplyChangesが呼び出されないためm_CurrValは更新されていないことになる。つまりスライダーを動かす前の値に戻ることになる。

1
2
3
4
5
6
7
8
HRESULT CMySourceExProp::OnDisconnect(void) {
    if(m_pColor) {
        m_pColor->SetColor(m_CurrVal);
        m_pColor->Release();
        m_pColor=NULL;
    }
    return S_OK;
}

使い方

regsvr32 でフィルタを登録したら graphedit で確認してみよう。

フィルタグラフを実行したままプロパティページを開き、スライダーを動かすと明るさが変化することを確認できる。

https://github.com/mahorigahama/mysourceexfilter


Comments

comments powered by Disqus