Microsoft DirectX 8.1 (C++)

Receiving Events in ATL

This topic applies to Windows XP Home Edition and Windows XP Professional only.

In ATL, you can create an event sink by deriving from the IDispEventImpl or IDispEventSimpleImpl class template. This section is a brief summary of this process. (For details, consult the ATL documentation.) This example uses IDispEventSimpleImpl to catch two events from the Video Control, _IMSVidCtlEvents::Click and _IMSVidCtlEvents::StateChange.

Include the class template in your client's inheritance list:

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

Define variables of type _ATL_FUNC_INFO to hold the type information for the events you want to support, and declare them as extern in your header file:

/* In your header file: */
extern _ATL_FUNC_INFO OnClickInfo;       // Click event.
extern _ATL_FUNC_INFO OnStateChangeInfo; // StateChange event.

/* In your source file: */
_ATL_FUNC_INFO OnClickInfo = {CC_STDCALL, VT_EMPTY, 0};
_ATL_FUNC_INFO OnStateChangeInfo = {CC_STDCALL, VT_EMPTY, 2, { VT_I4, VT_I4} };

Add entries for the two events in the event sink map:

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()

Define the event handler methods:

void __stdcall OnStateChange(MSVidCtlStateList PrevState, MSVidCtlStateList CurrState)
{
    // Call an application-defined function to update the UI.
     MyUpdateState(PrevState, CurrState);
}

void __stdcall OnVidCtlClick()
{
    // Beep when clicked.
    MessageBeep(MB_ICONHAND);
}

Set up the advise sink by calling the helper method IDispEventSimpleImpl::DispEventAdvise:

// Pass in a pointer to the Video Control.
hr = DispEventAdvise(m_pVideoControl); 

Remove the advise sink before shutting down:

if (m_pVideoControl)
{
    DispEventUnadvise(m_pVideoControl);
    m_pVideoControl->Stop();
    m_pVideoControl = NULL;
}

To catch events from more than one source, derive from multiple IDispEventSimpleImpl templates. For example, to catch conditional access events as well as Video Control events, you could use the following class declaration:

enum { VIDCTL_EVENTS, CA_EVENTS }; // Identify the sink. 
class CMyContainer;  // Forward declare.

// Some typedefs for convenience:
typedef IDispEventSimpleImpl<VIDCTL_EVENTS, CMyContainer,
    &__uuidof(_IMSVidCtlEvents)>  IDispEvent_VidCtl;
typedef IDispEventSimpleImpl<CA_EVENTS, CMyContainer, 
    &__uuidof(_ICAManagerEvents)> IDispEvent_CA;

// Class declaration:
class ATL_NO_VTABLE CMyContainer:
    /* .... */
    public IDispEvent_VidCtl,
    public IDispEvent_CA

Then set up the event sink map:

BEGIN_SINK_MAP(CMyContainer)
    // Video control events:
    SINK_ENTRY_INFO(VIDCTL_EVENTS, __uuidof(_IMSVidCtlEvents),
        DISPID_CLICK, OnVidCtlClick, &OnVidCtlClickInfo)
    // etc ...

    // Conditional access events:
   SINK_ENTRY_INFO(CA_EVENTS, __uuidof(_ICAManagerEvents), 2207,  
       OnRequestDenied, &OnRequestDeniedInfo)
    // etc ...
END_SINK_MAP()

When you call IDispEventSimpleImpl methods, such as DispEventAdvise, you will need to disambiguate which instance you are calling. For example:

HRESULT CMyContainer::SetupEvents()
{
    HRESULT hr = IDispEvent_VidCtl::DispEventAdvise(m_pMSVidCtl);
    if (SUCCEEDED(hr))
    {
        hr = IDispEvent_CA::DispEventAdvise(m_pCAManager);
    }
    return hr;
}