techvanguards.com
Last updated on 9/27/2002

Basic Event Concepts
by Binh Ly

If a client talks to a server through the server's interface, wouldn't it make sense that the server can also talk to the client through the client's interface? But wait, we never mentioned anything before about clients having any interfaces have we?

Let's look at it from another angle. If we reversed the roles for client and server in such a way that the server became the client and the client became the server, then the server now talks to the client in the normal client-to-server manner.

Figure: Client-to-server and server-to-client connection

In order for a client to become a server of the server, it has to expose an interface to the server. Once the server gets an interface from the client, it can then call any methods on the interface as if the client was its server. Got it? If not, read the last two statements three more times.

The idea is really simple: the client hands out an interface to the server. Whenever the server wants to chit-chat with the client, the server simply uses the interface it got from the client to call back into the client. To do this, the server must provide a method in its interface allowing the client to pass the client's interface into the server. Using our example on the Downloader object, the IDownloader interface must somehow provide a mechanism for a client to hand its interface to Downloader. One way to do this is:

IDownloader = interface
  procedure HereYouGo (ClientInterface);
  procedure GetFile (FileName);
end;

The client can then pass its interface to Downloader using pseudocode like this:

// create Downloader object
Downloader = CreateObject ("DownloaderServer.Downloader");
// pass client's interface into Downloader
Downloader.HereYouGo (MyInterface);
// perform download
Downloader.GetFile (HugeFileFromInternet);

To complete our Downloader object, assume that the client exposes this interface:

IDownloadListener = interface
  procedure UpdateProgress (Percent);
end;

Given IDownloadListener, IDownloader can now be implemented like this:

procedure Downloader.HereYouGo (ClientInterface);
begin
  Store ClientInterface in a DownloadListener local/object variable
end;

procedure Downloader.GetFile (FileName);
begin
  while (NotDoneDownloadingYet) do
  begin
    DownloadMoreBytes;
    // notify client (IDownloadListener) of progress
    DownloadListener.UpdateProgress (CalculateDownloadedPercentageSoFar);
  end;
end;

Very simple isn't it?

A Jazz Chat Room

Sometimes, it is necessary for several clients to connect to a single object so that they all receive events from that object. Consider a JazzChatRoom server object that represents a chat room for people who are interested in jazz music. Chatters (chat clients) who are interested in jazz can all meet in one JazzChatRoom - this means that all chat clients connect to one JazzChatRoom object.

Figure: Multiple chatters connecting to one JazzChatRoom

Now, if one of the chatters says something, it is JazzChatRoom's responsibility to broadcast what that chatter said to the rest of the crew. In other words, JazzChatRoom needs to maintain a list of (possibly more that one) clients so that it can call into each one of its clients when it needs to broadcast a chatter's message.

Based on this, here's one implementation of JazzChatRoom:

// client's interface
IChatter = interface
  procedure HeresAMessageFromFellowChatter (Message);
end;

// server's interface
IJazzChatRoom = interface
  procedure EnterChatRoom (Chatter);
  procedure BroadcastMessage (Message);
end;

procedure JazzChatRoom.EnterChatRoom (Chatter);
begin
  Store Chatter into a Chatters list
end;

procedure JazzChatRoom.BroadcastMessage (Message);
begin
  // iterate chatter list and notify each chatter
  For each Chatter in Chatters list
    Chatter.HeresAMessageFromFellowChatter (Message);
end;

A chatter who wishes to join the chat room would simply call EnterChatRoom to register itself into JazzChatRoom's client list:

// find JazzChatRoom instance and join it
JazzChatRoom = FindJazzChatRoom;
JazzChatRoom.EnterChatRoom (MyIChatterInterface);

And then when a chatter wishes to broadcast a message to his fellow chatters, he can simply say:

JazzChatRoom.BroadcastMessage ("Hello World!");

Based on JazzChatRoom's BroadcastMessage implementation above, the message will be sent to all chatters (including the broadcaster) through each chatter's IChatter interface. 

Where Are We?

I've just shown you the concept of role-reversal between client and server. In COM, it is absolutely possible for a client to give the server its interface making it a server of the server. Note how I use the term "role-reversal" here. As you shall see later, you'll encounter COM security issues that are explained in the context of client-to-server communication. When dealing with security issues, always remember that when the server calls back into the client, the server becomes a client and the client becomes a server.

Further Reading

  • Understanding ActiveX and OLE by David Chappell
  • Essential COM by Don Box
Copyright (c) 1999-2011 Binh Ly. All Rights Reserved.