Vous êtes sur la page 1sur 2

Takeaway: COM connection points provide greater flexibility than typical callback functions.

Find
out how connection points work and digest a generous helping of code.

Component Object Model (COM) connection points are interfaces that handle event callback
functions. If you work with the Win32 API, you are probably familiar with callback functions. They
show up frequently as parameters to functions, such as EnumWindows().

COM connection points, although more complicated than standard callback functions, provide
greater flexibility because all parameters and calls are executed using the COM subsystem. The
COM subsystem allows calls to execute correctly across process boundaries, which is not
possible with simple callback functions.

Interfaces and events


Before I dive into how you add COM connection points to your applications, you need to be
familiar with a little terminology—namely, interfaces and event types. Related methods are
grouped into interfaces. Often, interfaces on a COM object will be similar in scope to the public
methods in a C++ class. So a connection point groups a set of related events into a COM
interface.

For example, consider the C++ timer class in Listing A. The class includes the functions
SetExpiredProc(), SetTime(), Start(), and Stop(), as well as the constructor CExampleTimer() and
a protected member function RunTimer(). The timer also fires an event when it expires. A COM
interface describing this class would comprise only the public functions related to being a timer,
such as SetTime(), Start(), and Stop(). You could construct a COM connection point interface
containing a single method named TimerExpired().

Client server vs. sink source


In a typical COM application, a COM object acts as a server with a specific interface. Clients
connect to it and execute methods on the interface. When dealing with connection points,
however, the COM server advertises that it has events that it will fire off to any clients that want to
receive them. A client can receive a set of events if it exposes the event COM interface. When
referring to connection points, the server is called the source and the client is called the sink.

So the main difference between normal programming with COM in a standard client-server
system and using connection points is that in the standard client-server case, the server exposes
a list of methods that the client employs, and in the connection point case, the client exposes a
set of methods that the server uses.

Connecting a sink to a source


With the terminology under your belt, you can consider how connection points work. First, the
sink attaches itself to the source by implementing the IConnectionPointContainer interface on the
event source. The IConnectionPointContainer interface provides two methods:

*· FindConnectionPoint() allows a sink to ask the source if it fires off a specific set of
events.
*· EnumConnectionPoints() allows a sink to ask the source for all of its event types.

To keep things simple, assume that the event sink knows which set of events it wants and that it
will ask for just that set of events. In this case, the event sink will take advantage of only the
IConnectionPointContainer::FindConnectionPoint() method, passing in a unique identifier for the
event type COM interface. If everything succeeds, and the source supports the requested event
type, the sink receives a pointer to an IConnectionPoint interface.

The IConnectionPoint interface


The IConnectionPoint interface manages a connection’s lifetime and provides the following
methods:

*· Advise() attaches a sink to the connection point source.


*· Unadvise() detaches a sink from the connection point source.
*· GetConnectionPointContainer() returns an IConnectionPointContainer interface pointer
to the object that contains the connection point.
*· GetConnectionInterface() returns the unique identifier to its event type COM interface.
*· EnumConnections() allows the caller to get a list of all the sinks that are connected to
the connection point.

For this article, only the Advise() method and the Unadvise() methods are necessary. You
complete the attachment of the sink to the connection point source by employing the
IConnectionPoint::Advise() method of the interface returned from
IConnectionPointContainer::FindConnectionPoint(). The call to IConnectionPoint::Advise() needs
two parameters: the IUnknown interface pointer to the sink and a pointer to a DWORD datatype
(frequently used to store 4-byte values) for the source to initialize.

The sink depends on the DWORD initialized by the source in IConnectionPoint::Advise() as an


identifier. This identifier is used to detach the sink from the source when it no longer needs to
receive events. The sink detaches from the source simply by calling IConnectionPoint::Unadvise()
and passing in the DWORD. See Listing B for the code.

Firing events from the source to the sink


Now that you've seen how the event sink informs the source that it wants to receive events, you
can look at how that event source fires those events. The process begins with the implementation
of the IConnectionPoint::Advise() method. Remember that this method will call and pass in a
pointer to its IUnknown interface, as well as a pointer to a DWORD. The source simply needs to
store that IUnknown pointer in some data structure, possibly an array, and initialize the DWORD
to a value that identifies the IUnknown interface pointer, possibly its index in the array.

The last thing necessary for an event source to fire events to any listening sinks is a helper
method called Fire_EventX(), which is the name of a method in the COM event interface. This
method abstracts the EventX() calls on the sink objects that were stored during the execution of
the IConnectionPoint::Advise() method. After abstracting the objects, the event source fires off
events to all event sinks that care by calling Fire_EventX(), as shown in Listing C.

Conclusion
COM connection points offer a great deal of flexibility because the subsystem makes all function
calls so they will execute across processes. Once you get the hang of interfaces and event types,
you should be well on your way to taking advantage of this approach.

Vous aimerez peut-être aussi