Connectable Objects

The set of interfaces that a client can access through QueryInterface forms an object's incoming interfaces when calls to those interfaces come into the object. However, this alone is not entirely sufficient to completely describe the possible features of objects: sometimes an object will want to notify external clients when events happen in the object—for example, when data changes or when a user performs an action such as clicking the mouse on the object. In order to send such notifications (or to "fire events," as it is sometimes called), the object supports outgoing (sometimes called source) interfaces, illustrated as an arrow coming out of an object, as shown in Figure 1-8.

Figure 1-8.

An object's outgoing interfaces are drawn as outgoing arrows alongside the jacks that represent incoming interfaces.

Outgoing interfaces are not ones that the object implements itself. Instead, the object is a client of the interface as implemented on an external object. The most frequent use of this sort of relationship is the forming of a two-way channel of communication between two components, where each is both client and object. In order not to confuse the terminology, the object that sends the notifications is called the source, and the client that receives the notifications is called the sink, as illustrated in Figure 1-9.

Figure 1-9.

A client that implements an object's outgoing interface is a sink for the object's notifications and events.

What is special in this outgoing interface relationship that differentiates it from the usual incoming interfaces is that the object generally defines the exact outgoing interface itself. This is why we still call it the object's interface even though the client implements it—the object defines outgoing interfaces as part of its feature set.

The exact mechanism used to establish this two-way channel of communication is the technology called Connectable Objects, which is the topic of Chapter 4. When any object wants to express the fact that it has outgoing interfaces, it implements an interface named IConnectionPointContainer, and in doing so it qualifies as a connectable object. When a client wants to check whether an object has outgoing interfaces, that client will call QueryInterface, asking for IConnectionPointContainer. With this interface, the client can browse through individual entities called connection points; each connection point represents a single outgoing interface. These connection points are small objects themselves (with their own IUnknown behavior), managed within the larger object, each of which implements an interface named IConnectionPoint. It is through this interface that the client can ask the connection point for the identifier of its outgoing interface and give the connection point the interface pointer through which the connectable object sends notifications (that is, calls interface member functions). In other words, to establish the two-way channel, the client has to be able to pass its own interface pointers to the connectable object, and connection points are the means for doing so.

Some outgoing interfaces involved in a two-way dialogue are known to both sides at compile time. These are known as standard event sets, or standard notification interfaces, which are defined in header files. In other cases, however, the client does not know the exact details of the interface until run time, which requires the object to supply type information.

The idea of events, which connectable objects provide, is a very powerful one. So many things—controls, menus, the keyboard, the mouse, modems, power failures, bothersome relatives—generate events. Anything that somehow has something to say is an event source, and connection points are how you listen. What you do when you hear that a certain event has occurred is completely open. Events are really the triggers that make things happen and that transform user actions (such as typing, moving the mouse, and speaking into a microphone) into information that a piece of software can use as a stimulus to drive a particular response. Stimulus-response makes things seem alive. This makes events a key to dynamic software, and connectable objects are how events are implemented in OLE.