previous page
next page

Adding and Firing Events

When something interesting happens in a COM object, we'd like to be able to spontaneously notify its client without the client polling the object. COM provides a standard mechanism for sending these notifications to clients (normally called "firing an event") using the connection-point architecture.

Connection-point events are actually methods on an interface. To support the widest variety of clients, an event interface is often defined as a dispinterface. Choosing Support Connection Points in the ATL Simple Object Wizard generates an event in our IDL file. The following is an example of the wizard-generated code augmented with a single event method (shown in bold):

[
    uuid(B830F523-D87B-434F-933A-623CEF6FC4AA),
    helpstring("_ICalcPiEvents Interface")
]
dispinterface _ICalcPiEvents {
    properties:
    methods:
    [id(1)] void OnDigit([in] short nIndex,
        [in] short nDigit);
};

In addition to changing the IDL file, the Support Connection Points option makes several changes to the class definition. The IConnectionPointContainerImpl base class is added. This class implements the IConnectionPointContainer interface, providing functionality for managing multiple event interfaces on the class. The IConnectionPointImpl base class implements a connection point for a specific event interface: _ICalcPiEvents, in this case. The COM_MAP is also modified to include an entry for IConnectionPointContainer, and a new map, the CONNECTION_MAP, is added to the class.

The wizard also generates a proxy class for the connection point. This proxy class is added to the base class list and provides a convenient way to actually fire the events (that is, call the methods on the connection point). This is very helpful because the typical connection point is a dispinterface.

For example:

STDMETHODIMP CCalcPi::CalcPi(BSTR *pbstrPi) {
  // (code to calculate pi removed for clarity)
  ...
  // Fire each digit
  for( short j = 0; j != m_nDigits; ++j ) {
    Fire_OnDigit(j, (*pbstrPi)[j+2] - L'0');
  }

  ...
}

Objects of the CCalcPi class can now send events that can be handled in a page of HTML:

<object classid="clsid:E5F91723-E7AD-4596-AC90-17586D400BF7"
        id=objPiCalculator>
        <param name=digits value=50>
</object>

<input type=button name=cmdCalcPi value="Pi to 50 Digits:">
<span id=spanPi>unknown</span>

<p>Distribution of first 50 digits in pi:
<table border cellpadding=4>
... <!- table code removed for clarity >
</table>

<script language=vbscript>
  ' Handle button click event
  sub cmdCalcPi_onClick
    spanPi.innerText = objPiCalculator.CalcPi
  end sub

  ' Handle calculator digit event
  sub objPiCalculator_onDigit(index, digit)
    select case digit
    case 0: span0.innerText = span0.innerText + 1
    case 1: span1.innerText = span1.innerText + 1
    ... <! etc >
    end select
    spanTotal.innerText = spanTotal.innerText + 1
  end sub
</script>

The sample HTML page handles these events to provide the first 50 digits of pi and their distribution, as shown in Figure 1.11.

Figure 1.11. Pi to 50 digits


For more information about ATL's support for connection points, see Chapter 9, "Connection Points."


previous page
next page
Converted from CHM to HTML with chm2web Pro 2.75 (unicode)