Table of contents
1.
Introduction
2.
ATL and Event Handling
3.
Event Handling using IDispEventSimpleImpl
3.1.
Example
4.
Frequently Asked Questions
4.1.
What is an event dispatcher in C++?
4.2.
How do I create an ATL COM object in Visual C++?
4.3.
Does C++ support event handling?
5.
Conclusion
Last Updated: Mar 27, 2024
Easy

Event Handling using IDispEventSimpleImpl

Author Sanjana Yadav
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Hello Reader!!

As we know, Microsoft's Active Template Library is a collection of template-based C++ classes designed to make writing Component Object Model objects easier. To make this point even clearer, we have started with our interface implementations. Today, we will learn to implement the event-handling interface using the IDispEventSimpleImpl class. 

Event Handling using IDispEventSimpleImpl

So, let’s get started!

ATL and Event Handling

The Active Template Library (ATL) is a collection of template-based C++ classes that allow you to construct compact, efficient COM objects. It supports significant COM features such as stock implementations, dual interfaces, standard COM enumerator interfaces, connection points, tear-off interfaces, and ActiveX controls.

Events inform a client that something interesting has happened in the object, such as a property change or the user clicking a button. Events are very useful with COM controllers. COM objects fire events and no response from the client is required. In other words, they are only alerts. On the other hand, requests are how a COM object asks a query to the client and expects a response.

When we create our standard COM objects, we provide implementations for interfaces (specified in an IDL file) that we have written or given to us. Such implementations make it easier to create "incoming" interfaces. The term "incoming" implies that the object "listens" to its client. The client invokes interface methods and so "talks" to the object. Let us learn about these implementations of event-handling interfaces in ATL.

Event Handling using IDispEventSimpleImpl

When handling events using IDispEventSimpleImpl, you must:

  • Derive your class from the IDispEventSimpleImpl class.
  • Incorporate an event sink map into your class.
  • Create ATL FUNC INFO structures that describe the events.
  • Using the SINK ENTRY INFO macro, add entries to the event sink map.
  • Implement the methods that you want to work with.
  • Advise and unadvise the event source.

 

Let us see an example to understand the above steps better.

Example

The following example demonstrates how to handle the NameChange event generated by the Word's Application object. The EventsApp dispinterface defines this event as a method.

[ uuid(000209F7-0000-0000-C000-000000000046), hidden ]
dispinterface EventsApp {
properties:
methods:
    [id(0x00000001), restricted, hidden]
    void Begin();

    [id(0x00000002)]
    void Leave();

    [id(0x00000003)]
    void NameChange();
};

 

#import is used in this example to produce the necessary header files from Word's type library. One must supply the correct mso dll file if you wish to use this example with different versions of Word. Office 2000, for example, includes mso9.dll, while Office XP includes mso.dll. This code is a simplification of pch.h (stdafx.h in Visual Studio 2017 and earlier):

Simple.h contains the following code. Comments highlight the important code:

#pragma warning (disable : 4146)

// defining Paths to needed MS OFFICE files (you need to replace "MSO.DLL" and "MSWORD.OLB" with the actual paths of the files.)
#define _MSDLL_PATH "MSO.DLL"
// Deleting the *.tlh files when changing the 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)

In this example, the only type library information used is the CLSID of the Word Application object and the IID of the EventsApp interface. This information is only required during the compilation process.

// Declaration of class for the type information
extern _ATL_FUNC_INFO OnDocChangeInfo;
extern _ATL_FUNC_INFO OnQuitInfo;

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

DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLE)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(ClassSimple)
   COM_INTERFACE_ENTRY(ISwitch)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

   CComPtr<Word::_Application> m_pApp;

   // Event handlers
   // Declaration of __stdcall calling convention and
   // Declaration of dispinterface-style signature
   void __stdcall OnQuit()
   {
      Stop();
   }

   void __stdcall OnDocChange()
   {
     ATLASSERT(m_pApp != NULL);

      // Getting a pointer to the _Document interface on the active document
      CComPtr<Word::_Document> pDoc;
      m_pApp->get_ActiveDocument(&pDoc);

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

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

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

// Mapping from Word events to the event handler functions.
BEGIN_SINK_MAP(ClassSimple)
   SINK_ENTRY_INFO(/*nID =*/ 1, __uuidof(Word::ApplicationEvents), /*dispid =*/ 3, OnDocChange, &OnDocChangeInfo)
   SINK_ENTRY_INFO(/*nID =*/ 1, __uuidof(Word::ApplicationEvents), /*dispid =*/ 2, OnQuit, &OnQuitInfo)
END_SINK_MAP()

// ISwitch
public:
   STDMETHOD(Begin)()
   {
      // If an object already exists, simply return
      if (m_pApp)
         return S_OK;
     
      // Creating 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);

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

      // Calling advise
      // Forging a connection to enable us to receive events
      DispEventAdvise(m_pApp);

      return S_OK;
   }

   STDMETHOD(Stop)()
   {
      // Checking for an object to unadvise on
      if (!m_pApp)
         return S_OK;

      // Calling unadvise
      // Breaking the connection with the event source
      DispEventUnadvise(m_pApp);

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

      return S_OK;
   }
};


Simple.cpp contains the following code:
// Define the type info structure
_ATL_FUNC_INFO OnDocChangeInfo = {CC_STDCALL, VT_EMPTY, 0};
_ATL_FUNC_INFO OnQuitInfo = {CC_STDCALL, VT_EMPTY, 0};
// (do not require the two structures as they are the same)

Frequently Asked Questions

What is an event dispatcher in C++?

Event Dispatchers are an Actor communication mechanism in which one Actor broadcasts an event and notifies other Actors that are listening to that event.

How do I create an ATL COM object in Visual C++?

First, open the Visual C++ tab. Choose MFC/ATL. In Visual Studio 2019, go to File > New > Project, put "atl" in the search box, and then choose ATL Project.

Does C++ support event handling?

Native C++ classes (C++ classes that do not implement COM objects) can also handle events. Support for native C++ event handling is deprecated and will be removed in a future version.

Conclusion

In this article, we learned to implement the event-handling interface using the IDispEventSimpleImpl class. We saw an example to get a clear picture of this.
 

We hope this post has helped you better grasp the ATL event handling interface implementation. You can refer to our blogs to understand more about Interfaces and c++ concepts.


You can also visit our website to read more such blogs. Make sure you enroll in our courses, take mock tests, solve problems, and interview puzzles. Also, you can prepare for interviews with interview experiences and an interview bundle.

Keep learning and keep growing, Ninjas!

Thank you
Live masterclass