Some of these points are esoteric and could be ignored if you are
full up!
Unloading unused DLLs - garbage collection
So far we have only written very simple clients. If our client
was running 24 hours a day, 7 days a week, 52 weeks a year and
creating and releasing thousands of object references, it would be
very difficult for the client to keep track of which DLLs need to be
loaded and which don't. While objects are automatically garbage
collected on the release of the last interface pointer, there is no
automatic garbage collection of DLLs with no more objects to
service.
We could solve this by forcing the DLL to keep track of how many
of its objects have extant references held by the client. A global
DLL 'lock count' could be incremented when the first interface
reference is passed to a client for a given object. The same lock
count could decrement when an object deletes itself. The DLL would
also have to export a function for the client to call periodically
in order to establish whether the DLL could be unloaded. If the lock
count is zero, the answer is yes, else it is no.
This allows the client to be in charge of the garbage collection
strategy for objects and DLLs.
Unique interface ids
The Dynamic_cast() method and the out-of-band object creation
function both suffer from the same problem - passing a string as an
interface identifier. It is going to be difficult to guarantee that
there will not be a clash of interfaces with common names. What we
really need is a way to define interfaces uniquely within a certain
scope.
Thread-safety
None of our code is thread-safe!
Using the registry as an implementation class repository
We need a way of uniquely identifying different implementations
of IString to allow a client to choose the one they want. This
unique class implementation identifier could be used as a key into a
class repository, for instance the registry, which could contain the
location details of the server. It is also possible to imagine every
DLL providing standard exported functions for self-registration and
de-registration of these details. This paves the way to a standard
creation sequence for the client.
Location of objects
So far we have only looked at DLL-based objects, where the client
and the object are in the same address space. The client has a
direct reference to the object. Even this proved non-trivial when
the client and object were implemented in the same language - a
certain amount of standardization and programming discipline was
required! While direct access to an object is fast, it may not be
secure - there is no firewall between the client and the object.
An EXE-based object would live in a different address space from
the client and the client and server may well have different
security profiles. An EXE-based object could even be placed on a
different machine, remote from the client.
Mismatch of context
Ideally, the programming model used by the client to access an
object should be invariant to the location of the object. In fact,
where possible, both caller and object should be unaware of
impedance mismatch between them. Difference in location is just one
example of context mismatch.
To facilitate this charade, a level of indirection is needed that
can map between the runtime context the caller expects and the
runtime context needed by the object. The caller must think that it
is using the object in its own context. The object must think it is
being called from its own context.
Imagine that it was possible to unambiguously define all
characteristics of a class and its interfaces in some declarative
description language. In this case it would be simple for the
runtime to provide the right services for the class and
automatically provide the "proxy" and "stub" code to map between the
caller and the object when necessary. If such a description language
allowed us to abstract away details specific to each host platform,
such as calling conventions, a tool could be provided on each
platform that spits out the right implementation language mappings
for a given platform. Remember that on each different platform we
are probably going to have to re-compile anyway.
Congratulations, you have just implemented what is essentially a
COM component. It is missing some infrastructure glue and does not
address any of the shortcomings discussed previously, but it is
fundamentally a COM component.
If you have understood this, hopefully it will help to ease the
path into developing and using COM components. You have already been
exposed to many of the issues of COM development and have explored
some of the common techniques used too.
Next
we will look at how COM interfaces are implemented and used.

|