Introduction
We know that ATL stands for Active Template Library. It is a library with numerous classes that permit you to use, manipulate and implement Windows. It provides an impressive implementation that would not cause overhead on your code.
ATL includes a set of template-based C++ classes that simplify the programming of Component Object Model (COM) objects. COM is a necessary specification used in creating and consuming software components on Windows. It is highly recommended when you want to use ATL Window Classes to their fullest extent.

This article will discuss several aspects of one of the most important topics of Implementing the Event Handling Interface- Event Handling using IDispEventImpl.
Event Handling
Event Handling is the process of using, managing, and controlling events. Now, what are events?
Events notify the clients that some changes have been made in the object, such as a user clicking the button or a property change being occurred. Events are extremely useful with COM controllers.
If we create standard COM objects, we give implementations for interfaces along with them. Such implementations ease the creation of incoming interfaces.
Principles of Event Handling
The three guiding principles of Event Handling around which the whole process involves are:
- Adding the event interface.
- Informing the event source about the acceptance of events.
- Notifying the event source when no longer events are required.
Event Handling using IDispEventImpl
When handling events using IDispEventImpl, we will cover the following points.
- Deriving class from the IDispEventImpl class.
- Incorporating an event sink map into your class.
- Adding entries to the event sink map using the SINK_ENTRY or SINK_ENTRY_EX macro.
- Implementing the methods that you want to handle.
-
Advising and unadvising the event source.
Let us see an example to understand the above steps better.

Example
The example below shows how to handle the FileChange event initiated by a Word’s Application object. This event is present as a method on the AppEvents dispinterface. Use the C++ code below to start with the implementation.
[ uuid(000809F4-0000-0000-C000-000000000059), hidden ]
dispinterface AppEvents
{
properties:
methods:
[id(0x00000001), restricted, hidden]
void Start();
[id(0x00000002)]
void End();
[id(0x00000003)]
void FileChange();
};
We will import several packages and files to produce the necessary header files. Suppose you want to use this code in other versions of the Word other than the latest version. In that case, it is compulsory to specify the accurate mso dll file. Use the C++ code below to start importing.
//pragma warnings to handle exceptions
#pragma warning (disable : 4146)
// Paths to the necessary files
// replacing "MSO.DLL" and "MSEXAMPLE.OLB" with the original paths
#define _PATH "MSO.DLL"
// Delete *.tlh files when altering import qualifiers
#import _PATH rename("RGB", "RGBOriginal") rename("DocumentProperties", "Properties") raw_interfaces_only
#import "C:\Program Files\Files\Shared\VBA\VBA4\VBE4EXT.OLB" raw_interfaces_only
#define _B_PATH "EXAMPLE.OLB"
#import _B_PATH rename("ExitWindows", "Quit") rename("FindText", "Search") raw_interfaces_only
#pragma warning (default : 4146)
Use the C++ code below to continue with the implementation. The comments added can be referred in case of any doubt.
// Generating a LIBID manually
namespace Example
{
struct __declspec(uuid("000809F4-0000-0000-C000-000000000059"))
Library;
};
class ATL_NO_VTABLE Simple :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSimple, &CLID_Simple>,
public IDispatchImpl<ISwitch, &ID_ISwitch, &LIBID_EVENTLib>,
//Inheritance from IDispEventImpl
public IDispEventImpl</*nID*/ 1, CSimple, &__uuidof(Example::AppEvents2), &__uuido
f(Example::Library), /*wMajor*/ 8, /*wMinor*/ 1>
{
public:
CSimple()
{
}
DECLARE_RESOURCEID(IDR_SIMPLE)
DECLARE_FINAL_CONSTRUCT()
BEGIN_MAP(CSimple)
INTERFACE_ENTRY(ISwitch)
INTERFACE_ENTRY(IDispatch)
END_MAP()
CComPtr<Example::_Application> m_App;
// Event handlers
void __call OnQuit()
{
Stop();
}
void __call OnDocChange()
{
ASSERT(m_App != NULL);
// Fixing a pointer to the interface
CComPtr<Example::_Document> pD;
m_App->get_ActiveDocument(&pD);
CComBSTR bName;
if (pD)
pD->get_Name(&bName);
// Creating a string
CComBSTR bDisplay(_T("New title:\n"));
bDisplay += bName;
// Display the name to the user
USES_CONVERSION;
MessageBox(NULL, W2CT(bDisplay), _T("IDispEventImpl :Document Changed"), M
_OK);
}
// Fixing the mapping
BEGIN_MAP(CSimple)
SINK_ENTRY_EX(/*nID =*/ 1, __uuidof(Example::ApplicationEvents2), /*dispid =*/ 3,
OnDocChange)
SINK_ENTRY_EX(/*nID =*/ 1, __uuidof(Example::ApplicationEvents2), /*dispid =*/ 2,
OnQuit)
END_MAP()
// ISwitch
public:
STD(Start)()
{
// If object is already present, return
if (m_App)
return OK;
// Creating an instance
RESULT r = m_App.CoCreateInstance(__uuidof(Example::Application), NULL, CLSC
TX_SERVER);
if (FAILED(r))
return r;
ASSERT(m_App != NULL);
// Make the Example interface visible
m_App->put_Visible(true);
// Note call to advise
// Forge a connection to enable us to receive events
DispEventAdvise(m_App);
return OK;
}
STD(Stop)()
{
// Checking if we have to unadvise an object
if (!m_App)
return OK;
// Notifying unadvise
DispEventUnadvise(m_App);
// Releasing the application
m_App.Release();
return OK;
}
};



