Event Objects
Events are instances of event classes that implement the IEvent interface. The IEvent interface defines the Dispatch() method, which takes a pointer to the object handling the event and invokes the appropriate handler function. Events implement the Dispatch() method by querying the event handler for the appropriate event listener interface and then invoking the handler method on the interface. The relationship between events and event listeners is an example of the visitor design pattern.
Event classes are simply C++ classes that implement the IEvent interface. The Events package implements the most common Windows messages as event classes. Developers can create their own custom event types by implementing the IEvent interface and one or more corresponding event listener types.
Windows Messages
A Windows message is a type of event generated by the operating system and queued up for an application. The Windows Platform SDK defines constants using the naming convention WM_XXX for messages. The Events package defines the IWinEvent interface, which provides methods for accessing the message ID, WPARAM, LPARAM, and result value of a Windows message. All Window events implement the IWinEvent interface. The CWinEvent template class makes it easy to implement new Windows event classes by providing a default implementation of the IWinEvent interface.
Example 31 shows how the WM_PAINT message is implemented using the CWinEvent class. First, an interface is derived from IWinEvent that defines a method for cracking the WM_PAINT message.
Example 31 – Implementing the WM_PAINT message by using the CWinEvent class
class __declspec(uuid("8A6AF181-40A7-11d3-AF0D-006008AFE059"))
IWindowPaintEvent : public IWinEvent
{
public:
virtual HDC GetDC() const = 0;
};
Next, the class CWindowPaintEvent is derived from the CWinEventBase class, as shown in Example 32. The template parameters for CWinEventBase are the interface for the event and the GUID for that interface. The CWindowPaintEvent class implements the Dispatch() method inherited from IEvent and the GetDC() method inherited from IWindowPaintEvent.
Example 32 – Deriving CWindowPaintEvent from the CWinEventBase class
class CWindowPaintEvent : public CWinEventBase<IWindowPaintEvent,
&IID_IWindowPaintEvent>
{
virtual bool Dispatch(IQueryGuid* pIListener);
virtual HDC GetDC() const;
};
 
bool CWindowPaintEvent::Dispatch(IQueryGuid* pIListener)
{
bool bHandled = false;
IWindowListener* pIWindowListener =
guid_cast<IWindowListener*>(pIListener);
 
if (pIWindowListener != NULL)
{
bHandled = pIWindowListener->OnPaint(GetDC());
pIWindowListener->Release();
}
 
return bHandled;
}
 
HDC CWindowPaintEvent::GetDC() const
{
return (HDC) GetWParam();
}
The Event Factory
The CEventFactory class translates Windows messages into event objects. It contains a method named CreateWindowsEvent(), which takes a message ID, WPARAM, and LPARAM and creates the appropriate type of Windows event object. The CEventFactory class defines a virtual FilterWindowsEvent() method to provide derived classes the opportunity to filter events. Command messages are handled by the CreateCommandEvent() and FilterCommandEvent() methods. Example 33 shows the definition of the CEventFactory class.
Example 33 – CEventFactory class definition
class CEventFactory
{
public:
virtual bool FilterWindowsEvent(UINT message, WPARAM wParam,
LPARAM lParam);
virtual IEvent* CreateWindowsEvent(UINT message, WPARAM wParam,
LPARAM lParam);
virtual bool FilterCommandEvent(UINT nID, int nCode);
virtual IEvent* CreateCommandEvent(UINT nID, int nCode);
virtual IEvent* CreateCommandQueryEvent(UINT nID);
};
Windows Message Cracking
Message cracking is a natural by-product of encapsulating the WPARAM and LPARAM of a Windows event in an object. Calling member functions to crack a Windows message is more convenient and type-safe than using macros. Example 34 illustrates a window procedure that cracks mouse events and saves the point at which the mouse event occurred.
Example 34 – Windows procedure that cracks mouse events and saves the event point
static POINT g_ptLast;
 
LRESULT WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
static CEventFactory factory;
 
IEvent* pEvent = factory.CreateWindowsEvent(nMsg, wParam, lParam);
IMouseEvent* pMouseEvent = guid_cast<IMouseEvent*>(pEvent);
if (pMouseEvent != NULL)
{
pMouseEvent->GetPoint(g_ptLast);
}
. . .
}