Architecture of Connectable Objects
The connectable object itself is only one piece of the overall architecture of
connectable objects. This technology includes:
-
Connectable object
-
Implements the IConnectionPointContainer
interface; creates at least one connection point object; defines an outgoing
interface for the client.
-
Client
-
Queries the object for IConnectionPointContainer to determine if the
object is connectable; creates a sink object to implement the outgoing
interface defined by the connectable object.
-
Sink object
-
Implements the outgoing interface; used to establish a connection to the
connectable object.
-
Connection point object
-
Implements the IConnectionPoint interface and
manages connection with the client’s sink.
The relationships between client, connectable object, a connection point, and
a sink are illustrated in the following diagram:
Before the connection point object calls methods in the sink interface in step
3, it must QueryInterface for the specific interface required, even if
the pointer was already passed in the step 2 call to the Advise method.
Two enumerator objects are also involved in this architecture though not shown
in the illustration. One is created by a method in IConnectionPointContainer
to enumerate the connection points within the connectable object. The other is
created by a method in IConnectionPoint to enumerate the connections
currently established to that connection point. One connection point can
support multiple connected sink interfaces, and it should iterate through the
list of connections each time it makes a method call on that interface. This
process is known as multi-casting.
When working with connectable objects it is important to understand that the
connectable object, each connection point, each sink, and all enumerators are
separate objects with separate IUnknown implementations, separate
reference counts, and separate lifetimes. A client using these objects is
always responsible for releasing all reference counts it owns.
Note A connectable object can support more than one client and can
support multiple sinks within a client. Likewise, a sink can be connected to
more than one connectable object.
The steps for establishing a connection between a client and a connectable
object are:
-
The client queries for IConnectionPointContainer on the object to
determine if the object is connectable. If this call is successful, the client
holds a pointer to the IConnectionPointContainer interface on the
connectable object, and the connectable object reference counter has been
incremented. Otherwise, the object is not connectable and does not support
outgoing interfaces.
-
If the object is connectable, the client next tries to obtain a pointer to the
IConnectionPoint interface on a connection point within the connectable
object. There are two methods for obtaining this pointer, both in IConnectionPointContainer
&emdash; FindConnectionPoint and EnumConnectionPoints. There are
a few additional steps needed if EnumConnectionPoints is used; see
below for more information. If successful, the connectable object and the
client both support the same outgoing interface. The connectable object
defines it and calls it while the client implements it. The client can then
communicate through the connection point within the connectable object.
-
The client then calls IConnectionPoint::Advise on the connection point
to establish a connection between its sink interface and the object’s
connection point. After this call, the object’s connection point holds a
pointer to the outgoing interface on the sink.
-
The code inside IConnectionPoint::Advise calls QueryInterface on
the interface pointer that is passed in, asking for the specific interface
identifier to which it connects.
-
The object calls methods on the sink’s interface as needed using the pointer
held by its connection point.
-
The client calls IConnectionPoint::Unadvise to terminate the
connection. Then, the client calls IConnectionPoint::Release to free
its hold on the connection point and, thus, the main connectable object also.
The client must also call IConnectionPointContainer::Release to free
its hold on the main connectable object.