Using IDispEventSimpleImpl

Event Handling and ATL

When using IDispEventSimpleImpl to handle events, you will need to:

Example

The example below shows you how to handle the DocumentChange event fired by Word's Application object. This event is defined as a method on the ApplicationEvents dispinterface:

[
  uuid(000209F7-0000-0000-C000-000000000046),
  hidden
]
dispinterface ApplicationEvents {
    properties:
    methods:
        [id(0x00000001), restricted, hidden]
        void Startup();
        [id(0x00000002)]
        void Quit();
        [id(0x00000003)]
        void DocumentChange();
};

The example uses #import to generate the required header files from Word's type library:

#pragma warning (disable : 4146)
#import "C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\MSO97.DLL" raw_interfaces_only
#import "C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\VBA\VBEEXT1.OLB" raw_interfaces_only
#import "C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\MSWORD8.OLB" rename("ExitWindows", "WordExitWindows") raw_interfaces_only
#pragma warning (default : 4146)

The only information from the type library actually used in this example is the CLSID of the Word Application object and the IID of the ApplicationEvents interface. This information is only used at compile time.

The following code appears in Simple.h. The relevant code is in bold:

// Declare structure for type information
extern _ATL_FUNC_INFO OnDocChangeInfo;

class ATL_NO_VTABLE CSimple : 
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CSimple, &CLSID_Simple>,
   public IDispatchImpl<ISwitch, &IID_ISwitch, &LIBID_DISPEVENTLib>,
   public IDispEventSimpleImpl</*nID =*/ 1, CSimple, &__uuidof(Word::ApplicationEvents)>
{
public:
   CSimple()
   {
   }

DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLE)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSimple)
   COM_INTERFACE_ENTRY(ISwitch)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

   CComPtr<Word::_Application> m_pApp;

   // Event handler
   // Note the __stdcall calling convention and 
   // dispinterface-style signature
   void __stdcall OnDocChange()
   {
      // Get a pointer to the _Document interface on the active document
      CComPtr<Word::_Document> pDoc;
      m_pApp->get_ActiveDocument(&pDoc);

      // Get the name from the active document
      CComBSTR bstrName;
      pDoc->get_Name(&bstrName);

      // Create a display string
      CComBSTR bstrDisplay(_T("New document title:\n"));
      bstrDisplay += bstrName;

      // Display the name to the user
      USES_CONVERSION;
      MessageBox(NULL, W2CT(bstrDisplay), _T("Active Document Changed"), MB_OK);
   }

BEGIN_SINK_MAP(CSimple)
   SINK_ENTRY_INFO(/*nID =*/ 1, __uuidof(Word::ApplicationEvents), /*dispid =*/ 3, OnDocChange, &OnDocChangeInfo)
END_SINK_MAP()

// ISwitch
public:
   STDMETHOD(Start)()
   {
      // If you already have an object, just return
      if (m_pApp)
         return S_OK;
      
      // Create an instance of Word's Application object
      m_pApp.CoCreateInstance(__uuidof(Word::Application), NULL, CLSCTX_SERVER);

      // Make the Word user interface visible
      m_pApp->put_Visible(true);

      // Forge a connection to enable you to receive events
      DispEventAdvise(m_pApp);

      return S_OK;
   }

   STDMETHOD(Stop)()
   {
      // Check you have an object to unadvise on
      if (!m_pApp)
         return S_OK;

      // Break the connection with the event source
      DispEventUnadvise(m_pApp);

      // Release the Word application
      m_pApp.Release();

      return S_OK;
   }
};

The following code is from Simple.cpp:

// Define type info structure
_ATL_FUNC_INFO OnDocChangeInfo = {CC_STDCALL, VT_EMPTY, 0};

See Also

The ATLEventHandling Sample