次の方法で共有


ATL でのビデオ コントロール イベントの受け取り

このトピックは Windows XP にのみ適用。

ビデオ コントロールはディスプインターフェイスである _IMSVidCtlEvents を介してクライアントにイベントを送信する。ATL では、IDispEventImpl または IDispEventSimpleImpl クラス テンプレートからの派生によってディスプインターフェイス イベント シンクを作成できる。これらのクラスの利点の 1 つは、すべてのイベントに対してメソッドを実装する必要がないことである。受け取るイベントだけに対して実装すればよい。

このセクションではこの処理の概要を簡単に説明する。詳細については、ATL のドキュメントを参照すること。この例では、IDispEventSimpleImpl を使って _IMSVidCtlEvents::Click および _IMSVidCtlEvents::StateChange という 2 つのイベントをビデオ コントロールから捕捉している。

最初に、クライアントの継承リストにクラス テンプレート IDispEventSimpleImpl を追加する。

class ATL_NO_VTABLE CMyContainer :
    /* ... */
    public IDispEventSimpleImpl<IDC_MSVIDCTL1, CMyContainer, 
        &__uuidof(_IMSVidCtlEvents)>

最初のパラメータはフォーム内のビデオ コントロールのリソース ID である。2 番目のパラメータは複合コントロール クラスの名前を指定する。3 番目のパラメータはイベント インターフェイスの IID である。

次に、サポートするイベントのタイプ情報を保持する _ATL_FUNC_INFO 型の変数を定義する。この変数をヘッダー ファイルで extern として宣言する。

/* ヘッダー ファイル内で: */
extern _ATL_FUNC_INFO OnClickInfo;       // Click イベント。
extern _ATL_FUNC_INFO OnStateChangeInfo; // StateChange イベント。

/* ソース ファイル内で: */
_ATL_FUNC_INFO OnClickInfo = {CC_STDCALL, VT_EMPTY, 0};
_ATL_FUNC_INFO OnStateChangeInfo = {CC_STDCALL, VT_EMPTY, 2, { VT_I4, VT_I4} };

_ATL_FUNCT_INFO 変数はイベント インターフェイス内の 1 つのメソッドのタイプ情報を指定する。この情報は、呼び出し規則 (常に CC_STDCALL)、戻り型、パラメータの数、および型の配列 (各パラメータにつき 1 つ) から成る。

次に、イベント シンク マップに 2 つのイベントのエントリを追加する。

BEGIN_SINK_MAP(CMyContainer)
   SINK_ENTRY_INFO(0, __uuidof(_IMSVidCtlEvents),
       DISPID_CLICK, OnClick, &OnClickInfo)
   SINK_ENTRY_INFO(0, __uuidof(_IMSVidCtlEvents), 
       dispidStateChange, OnStateChange, &OnStateChangeInfo)
END_SINK_MAP()

複合コントロール クラスにイベント ハンドラ メソッドを定義する。

void __stdcall OnStateChange(MSVidCtlStateList PrevState, MSVidCtlStateList CurrState)
{
          // アプリケーション定義の関数を呼び出して UI を更新する。
     MyUpdateState(PrevState, CurrState);
}

void __stdcall OnClick()
{
          // アプリケーション定義の関数を呼び出して UI を更新する。 
     MyHandleClick();
}

ATL はウィンドウを表示するときに、自動的に接続を設定し、コントロールをアンロードするときに、自動的に接続を解除する。

デュアル インターフェイス イベント

デバイスやフィーチャーなどの他のビデオ コントロール オブジェクトは、ディスプインターフェイスではなくデュアル インターフェイスを介してイベントを送信する。 (ディスプインターフェイスIDispatch::Invoke メソッドを介してのみ呼び出され、vtable を使わない。デュアル インターフェイスInvoke メソッドまたは vtable のいずれかを介して呼び出すことができる。)

ATL では、IDispatchImpl クラス テンプレートを使ってデュアル インターフェイス イベントを処理できる。以下では、MSVidFilePlaybackDevice オブジェクトから IMSVidFilePlaybackEvent インターフェイスを使ってファイル再生イベントを受け取る方法を説明する。

最初に、IDispatchImpl クラスを継承リストに追加する。

    public IDispatchImpl<
              IMSVidFilePlaybackEvent,  // シンクする対象のイベント インターフェイス。
              &__uuidof(IMSVidPlaybackEvent), // インターフェイスの IID。 
              &LIBID_MSVidCtlLib, /*wMajor =*/ 1, /*wMinor =*/ 0  // Typelib
    >

IMSVidFilePlaybackEvent インターフェイスをコンポーネントの COM マップに追加する。

BEGIN_COM_MAP(CMyControl)
    /* ... */
    COM_INTERFACE_ENTRY(IMSVidFilePlaybackEvent)
    /* ... */
END_COM_MAP()

COM マップに IDispatch のエントリが既にある場合は、この変更によって次のようなコンパイル エラーが発生する可能性がある。

    error C2594: 'static_cast' : ambiguous conversions from
    'CMyControl::_ComMapClass *' to 'IDispatch *'

このエラーは、コントロールが複数のインターフェイスを介して IDispatch を継承する場合に発生する。これを修正するには、COM_INTERFACE_ENTRY2 マクロを使って継承の分岐の 1 つを選択する。

    COM_INTERFACE_ENTRY2(IDispatch, IMSVidFilePlaybackEvent)

次に、イベント インターフェイスによって定義されたメソッドを実装する (IDispatch または IUnknown メソッドの実装は不要)。IMSVidFilePlaybackEvent の場合、インターフェイスは EndOfMedia という 1 つのイベントを定義する。

STDMETHODIMP EndOfMedia(IMSVidPlayback *pPlayback)
{ 
        /* 任意の処理を実行する。 */
    return S_OK;
}

イベントを受け取るには、イベントを起動するオブジェクトに対して AtlAdvise 関数を呼び出す。

// クラス メンバ変数
CComPtr<IMSVidFilePlayback> m_pFilePlayback;
DWORD m_dwFileSinkCP; // 接続ポイント cokkie を保持する。

// イベントをシンクするコード。 最初に、MSVidFilePlaybackDevice 
// オブジェクトがアクティブな入力かどうかを確認する。 アクティブな入力であれば、
// そのオブジェクトの IMSVidFilePlayback を問い合わせることができる。
CComPtr<IMSVidInputDevice> pInputDevice;
HRESULT hr = pVidControl->get_InputActive(&pInputDevice);
if (SUCCEEDED(hr))
{
        m_pFilePlayback = pInputDevice; // 暗黙の QueryInterface。
    if (m_pFilePlayback)
    {
                // IUnknown インターフェイスを問い合わせる。
        CComPtr<IUnknown> pUnk;
        this->QueryInterface(IID_IUnknown, (void**)&pUnk);
                // 接続ポイントを確立する。
        hr = AtlAdvise(m_pFilePlayback, pUnk,
            __uuidof(IMSVidFilePlaybackEvent), &m_dwFileSinkCP);
    }
}

オブジェクトを解放する前に、AtlUnadvise を呼び出して接続ポイントを解放する。

if (m_pFilePlayback)
{
    AtlUnadvise(m_pFilePlayback, 
        __uuidof(IMSVidFilePlaybackEvent), m_dwFileSinkCP);
    m_pFilePlayback.Release();
}