Using IDispEventImpl
The new home for Visual Studio documentation is Visual Studio 2017 Documentation on docs.microsoft.com.
The latest version of this topic can be found at Using IDispEventImpl (ATL).
When using IDispEventImpl to handle events, you will need to:
Derive your class from IDispEventImpl.
Add an event sink map to your class.
Add entries to the event sink map using the SINK_ENTRY or SINK_ENTRY_EX macro.
Implement the methods that you're interested in handling.
Advise and unadvise the event source.
The example below shows how to handle the DocumentChange event fired by Word's Application object. This event is defined as a method on the ApplicationEvents dispinterface.
The example is from the ATLEventHandling sample.
[
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. If you want to use this example with other versions of Word, you must specify the correct mso dll file. For example, Office 2000 provides mso9.dll and OfficeXP provides mso.dll. This code is simplified from stdafx.h:
#pragma warning (disable : 4146) // Paths to required MS OFFICE files (replace "MSO.DLL" and "MSWORD.OLB" with the actual paths to those files...) #define _MSDLL_PATH "MSO.DLL" // Delete the *.tlh files when changing import qualifiers #import _MSDLL_PATH rename("RGB", "MSRGB") rename("DocumentProperties", "WordDocumentProperties") raw_interfaces_only #import "C:\Program Files\Common Files\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB" raw_interfaces_only #define _MSWORDOLB_PATH "MSWORD.OLB" #import _MSWORDOLB_PATH rename("ExitWindows", "WordExitWindows") rename("FindText", "WordFindText") raw_interfaces_only #pragma warning (default : 4146)
The following code appears in NotSoSimple.h. The relevant code is noted by comments:
// Note #import doesn't generate a LIBID (because 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_ATLEVENTHANDLINGLib>, // Note inheritance from IDispEventImpl public IDispEventImpl</*nID*/ 1, CNotSoSimple, &__uuidof(Word::ApplicationEvents2), &__uuidof(Word::Library), /*wMajor*/ 8, /*wMinor*/ 1> { 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 handlers // Note the __stdcall calling convention and // dispinterface-style signature void __stdcall OnQuit() { Stop(); } void __stdcall OnDocChange() { ATLASSERT(m_pApp != NULL); // 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; if (pDoc) 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("IDispEventImpl : Active Document Changed"), MB_OK); } // Note the mapping from Word events to our event handler functions. BEGIN_SINK_MAP(CNotSoSimple) SINK_ENTRY_EX(/*nID =*/ 1, __uuidof(Word::ApplicationEvents2), /*dispid =*/ 3, OnDocChange) SINK_ENTRY_EX(/*nID =*/ 1, __uuidof(Word::ApplicationEvents2), /*dispid =*/ 2, OnQuit) END_SINK_MAP() // ISwitch public: STDMETHOD(Start)() { // If we already have an object, just return if (m_pApp) return S_OK; // Create an instance of Word's Application object HRESULT hr = m_pApp.CoCreateInstance(__uuidof(Word::Application), NULL, CLSCTX_SERVER); if (FAILED(hr)) return hr; ATLASSERT(m_pApp != NULL); // Make the Word user interface visible m_pApp->put_Visible(true); // Note call to advise // Forge a connection to enable us to receive events DispEventAdvise(m_pApp); return S_OK; } STDMETHOD(Stop)() { // Check we have an object to unadvise on if (!m_pApp) return S_OK; // Note call to unadvise // Break the connection with the event source DispEventUnadvise(m_pApp); // Release the Word application m_pApp.Release(); return S_OK; } };