次の方法で共有


IBroadcastEvent インターフェイス

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

IBroadcastEvent インターフェイスは、オブジェクトが直接接続ポイントを設定せずに別のオブジェクトからイベントを受信できるようにする。アプリケーションは、通常このインターフェイスを使う必要はない。

IUnknown から継承したメソッドに加えて、IBroadcastEvent インターフェイスは次のメソッドを公開する。

メソッド 説明
Fire イベントを発生させる。

注意

ブロードキャスト イベントによって、DirectShow フィルタ、ビデオ コントロールの機能、ビデオ コントロール デバイス オブジェクトの間で通信が可能になる。ブロードキャスト イベントを送信するために、オブジェクトはブロードキャスト イベント サービス オブジェクトの IBroadcastEvent::Fire を呼び出す。他のオブジェクトは、ブロードキャスト イベント サービス オブジェクトとの接続ポイントを設定することによってイベントの発生を待機できる。リスナは IBroadcastEvent を実装し、新しいブロードキャスト イベントが発生するたびに、ブロードキャスト イベント サービス オブジェクトはリスナの Fire メソッドを呼び出す。

ブロードキャスト イベントは次のような理由で便利である。

  • DirectShow のイベント メカニズムである IMediaEventSink は、複数のリスナをサポートしていない。DirectShow イベントはキューに入れられ、イベントを取得するとキューから削除される。
  • COM 接続ポイントは、ソース オブジェクトを特定するシンク オブジェクトを必要とする。ブロードキャスト イベントを使うと、ブロードキャスト イベント サービスはソース オブジェクトとシンク オブジェクトとの中継点として機能する。
  • 接続ポイントでは、ソースは、シンクが接続を確立するために使ったスレッドと同じスレッドでイベントを発生させるか、またはイベント インターフェイス ポインタをマーシャリングする必要がある。フィルタ グラフはマルチスレッド化されているので、ブロードキャスト イベント サービス オブジェクトは必要なマーシャリングを実装している。ブロードキャスト イベント サービス オブジェクトは、バックグラウンド スレッドを使って、登録されているすべてのリスナにイベントを配信する。

IBroadcastEvent インターフェイスはサービスであり、フィルタ グラフ マネージャの IServiceProvider インターフェイスを介して取得できる。そのためには、IServiceProvider::QueryService を呼び出して、次の値を指定する。

  • サービス識別子 :SID_SBroadcastEventService
  • インターフェイス識別子 :IID_IBroadcastEvent

QueryService の失敗コードは、オブジェクトがフィルタ グラフ マネージャにブロードキャスト イベント サービス オブジェクトを登録していないことを示す。この場合は、次の作業を行う。

  1. CoCreateInstance を使って、新しいブロードキャスト イベント サービス オブジェクトを作成する。
  2. フィルタ グラフ マネージャに IRegisterServiceProvider を照会する。
  3. サービス識別子を指定して IRegisterServiceProvider::RegisterService を呼び出す。

IBroadcastEvent インターフェイスへのポインタを取得したら、そのポインタを使ってイベントを送信するか、イベントをシンクすることができる。イベントを送信するには、Fire メソッドを呼び出す。イベントをシンクするには、シンク オブジェクトに IBroadcastEvent を実装し、ブロードキャスト イベント サービスに IConnectionPoint を照会し、IConnectionPoint::Advise を呼び出して接続を確立する。定義済みのブロードキャスト イベントの一覧については、「IBroadcastEvent::Fire」を参照すること。

サンプル コード

次の例では、ブロードキャスト イベントを送信またはシンクできるクラスを実装する。

class TunerEvent : public IBroadcastEvent
{

private:
    long m_nRefCount; // 参照カウントを保持する。
public:
    // IUnknown メソッド
    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&m_nRefCount);
    }
    STDMETHODIMP_(ULONG) Release()
    {
        _ASSERT(m_nRefCount >= 0);
        ULONG uCount = InterlockedDecrement(&m_nRefCount);
        if (uCount == 0)
        {
            delete this;
        }
        // スレッド セーフのために、メンバ変数ではなく、
        // 一時変数を返す。
        return uCount;
    }
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
    {
        if (NULL == ppvObject)
            return E_POINTER;
        if (riid == __uuidof(IUnknown))
            *ppvObject = static_cast<IUnknown*>(this);
        else if (riid == __uuidof(IBroadcastEvent))
            *ppvObject = static_cast<IBroadcastEvent*>(this);
        else 
            return E_NOINTERFACE;
        AddRef();
        return S_OK;
    }

    // IBroadcastEvent メソッド
    STDMETHOD(Fire)(GUID eventID)
    {
        // イベントを定義した
        if (eventID == EVENTID_TuningChanged)
        {
            // チューナーが局またはチャンネルを変更した。
        }
        
        return S_OK;
    }

    TunerEvent() : m_dwBroadcastEventCookie(0), m_nRefCount(1) {};

private:
    HRESULT HookupGraphEventService(IFilterGraph *pGraph);
    HRESULT RegisterForTunerEvents();
    HRESULT UnRegisterForTunerEvents();
    HRESULT Fire_Event(GUID eventID);

    CComPtr<IBroadcastEvent>   m_spBroadcastEvent; 
    DWORD m_dwBroadcastEventCookie;
};

// フィルタ グラフ マネージャにブロードキャスト イベント サービスを問い合わせる。
// 見つからない場合は、ブロードキャスト イベント サービスを作成して登録する。
HRESULT TunerEvent::HookupGraphEventService(IFilterGraph *pGraph)
{
    HRESULT hr = S_OK;
    if (!m_spBroadcastEvent)
    {
        CComQIPtr<IServiceProvider> spServiceProvider(pGraph);
        if (!spServiceProvider)
        {
            return E_NOINTERFACE;
        }
        hr = spServiceProvider->QueryService(SID_SBroadcastEventService, 
            IID_IBroadcastEvent, 
            reinterpret_cast<void**>(&m_spBroadcastEvent));
        if (FAILED(hr))
        {
            // ブロードキャスト イベント サービス オブジェクトを作成する。
            hr = m_spBroadcastEvent.CoCreateInstance(
                CLSID_BroadcastEventService,
                NULL, CLSCTX_INPROC_SERVER);
            if (FAILED(hr))
            {
                return hr; 
            }
            
            CComQIPtr<IRegisterServiceProvider> spRegService(pGraph);
            if (!spRegService)
            {
                return E_NOINTERFACE;
            }
            
            // ブロードキャスト イベント サービス オブジェクトをサービスとして登録する。
            hr = spRegService->RegisterService(
                SID_SBroadcastEventService,
                m_spBroadcastEvent);
        }
    }
    return hr;
}

// イベントを受信するための接続ポイントを確立する。
HRESULT TunerEvent::RegisterForTunerEvents()
{
    if (!m_spBroadcastEvent)
    {
        return E_FAIL;  // HookupGraphEventService の呼び出しを忘れた。
    }
    if(m_dwBroadcastEventCookie)
    {
        return S_FALSE;  // 既に接続が存在する場合は、何もしない。
    }
    CComQIPtr<IConnectionPoint> spConnectionPoint(m_spBroadcastEvent);
    if(!spConnectionPoint)
    {
        return E_NOINTERFACE;
    }
    return spConnectionPoint->Advise(static_cast<IBroadcastEvent*>(this),
        &m_dwBroadcastEventCookie);
}

// イベント用に登録を解除する。
HRESULT TunerEvent::UnRegisterForTunerEvents()
{
    HRESULT hr = S_OK;
    if(!m_dwBroadcastEventCookie)
    {
        return S_OK; // イベント用に登録されていない場合は、何もしない。
    }
    CComQIPtr<IConnectionPoint> spConnectionPoint(m_spBroadcastEvent);
    if(!spConnectionPoint)
    {
        return E_NOINTERFACE;
    }
    
    // 接続ポイントを解放する。
    hr = spConnectionPoint->Unadvise(m_dwBroadcastEventCookie);
    if (FAILED(hr))
    {
        // エラー : 接続ポイントのアドバイズを解除できない。
        return hr;
    }
    m_dwBroadcastEventCookie = 0;
    m_spBroadcastEvent.Release();
    return S_OK;
}

// ソース オブジェクトのイベントを送信する。
HRESULT TunerEvent::Fire_Event(GUID eventID)
{
    if (!m_spBroadcastEvent)
    {
        return E_FAIL; // HookupGraphEventService の呼び出しを忘れた。
    }
    return m_spBroadcastEvent->Fire(eventID);
}