The IConnectionPointContainer Interface

The outgoing arrows shown in the previous figures represent the fact that the object contains code to call the member functions of outgoing interfaces when necessary. In and of itself, however, this doesn't help the client know which outgoing interfaces the object supports.

IConnectionPointContainer allows the client to ask a connectable object a few questions about outgoing interfaces. Of course, a client must request this interface from an object by first calling QueryInterface(IID_IConnectionPointContainer), which asks the object, "Are you a connectable (source) object?"—that is, "Do you have any outgoing interfaces?" If an object replies with an error, it has no outgoing interfaces at all. Otherwise, you're given a pointer through which you can ask two other questions about the outgoing interfaces, expressed through the two specific members of IConnectionPointContainer (shown in this code and in Table 4-1):


interface IConnectionPointContainer : IUnknown
{
HRESULT EnumConnectionPoints(IEnumConnectionPoints **);
HRESULT FindConnectionPoint (REFIID, IConnectionPoint **);
};

Member Function

Description

FindConnectionPoint

"Do you have this specific outgoing interface?" Asks the object whether it supports the outgoing interface identified with an IID, returning an IConnectionPoint pointer if so.

EnumConnectionPoints

"Which outgoing interfaces do you support?" Creates and returns an enumerator object that implements IEnumConnectionPoints, through which the client can retrieve the IConnectionPoint pointers for each outgoing interface.


Table 4-1.

Member functions of IConnectionPointContainer.

To clarify the operations involved here, consider again the analogy of two humans trying to communicate with one another, as we described in Chapter 2. When I walk up to another person and perform the equivalent of QueryInterface for a human language, I'm asking specifically whether that person can understand that language. I'm not asking whether the person can speak the language, only whether he or she understands it. If I query for IConnectionPointContainer, I'm asking, "Can you speak?" and if so, I can ask, "Do you speak <language>?" and "What languages do you speak?"

With a positive response to either of the latter two questions, I get back a connection point. With that connection point, I can indicate my ability to understand that language myself. Again, you'll notice a decoupling of the process of asking a question—that is, exploring an object—and the process of actually performing some action. I could, if I wanted, ask whether you speak classical Latin. If you answered yes, I might say, "That's nice, too bad I don't understand it!" (It is, of course, a waste of time to write a program that works that way.)

Getting back a connection point is similar to being handed a jack into which I can plug a set of headphones that I can use to hear what the object has to say. Unless I plug into that jack, I won't hear a thing. This socket happens to be a pointer to IConnectionPoint, so let's see what that interface does.