Using IDispEventImpl

Event Handling and ATL

When using IDispEventImpl 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 following code appears in NotSoSimple.h. The relevant code is in bold:

// #import doesn't generate a LIBID (since we don't use 'named_guids'),
// so we have to do it manually
namespace Word
{
   struct __declspec(uuid("00020905-0000-0000-C000-000000000046"))
      /* library */ Library;
};

class ATL_NO_VTABLE CNotSoSimple : 
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CNotSoSimple, &CLSID_NotSoSimple>,
   public IDispatchImpl<ISwitch, &IID_ISwitch, &LIBID_DISPEVENTLib>,
   public IDispEventImpl</*nID*/ 1, CNotSoSimple,
            &__uuidof(Word::ApplicationEvents),
            &__uuidof(Word::Library), /*wMajor*/ 8, /*wMinor*/ 0>
{
public:
   CNotSoSimple()
   {
   }

DECLARE_REGISTRY_RESOURCEID(IDR_NOTSOSIMPLE)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CNotSoSimple)
   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(CNotSoSimple)
   SINK_ENTRY_EX(/*nID =*/ 1, __uuidof(Word::ApplicationEvents), /*dispid =*/ 3, OnDocChange)
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;
   }
};

See Also

ATLEventHandling Sample