To represent the interfaces that a COM component supports, we use a simple, pictorial technique called lollipop diagrams. A lollipop diagram represents the component in the form of a box; the interfaces extrude from the left side of the component. A name that appears within the box is the name of the component. The single line sprouting from the top of box represents an interface called IUnknown – this is a rather special interface in COM, so it gets special attention in lollipop diagrams.
Every component implements IUnknown, but programming languages like Visual Basic shield us from IUnknown and other COM-specific workings on the supposition that they’re difficult to understand. We could explain IUnknown here, but there’s no gain, because we’ll be using Visual Basic until Chapter 10. We’ll come back to talk about IUnknown in some detail in Chapter 10, when we start using C++.
The following figure shows the lollipop diagrams for the car and the truck in our example. Both components provide all the basic functionality needed to drive such a vehicle.
It’s not a great diagram, but it clearly shows what we can do with our vehicles. Let’s look at a more realistic lollipop diagram for our car example. Interfaces generally group together related functionality, so in the following we have three interfaces (or four, if you include IUnknown extruding from the top):
One interface provides methods for driving the car, another for controlling the locks and the alarm, and yet another for controlling the in-car music system.
Identifying the Component
IDrive is quite a nice name for our driving interface. The trouble is, it’s such an obvious name that it wouldn’t be at all surprising if someone else designed an interface of their own that did something similar, and they might call it IDrive as well. That’s going to cause severe problems if a component that exposes my IDrive gets installed on the same machine as a component that exposes this other developer’s IDrive interface. An application could easily end up talking to the ‘wrong’ interface – which will almost inevitably cause it to crash.
COM resolves such problems by ensuring that each COM interface (and, for that matter, each component) has a ‘real’ name that is guaranteed to be unique. An interface’s unique name is called an interface identifier (IID), and a component’s unique name is called a class identifier (CLSID). IIDs and CLSID are both types of globally unique identifier (GUID); a GUID is a 128-bit number that can be generated with special a utility supplied by Microsoft.
For example, the IID for my IDrive might be 67741683-547D-11D0-8236-00A0C908DB96. Inspection alone should tell you that it’s more than a little unlikely anyone else will come up with that name by chance.
The utility that generates GUIDs does so partly at random, and partly by scrambling information like the address of the Ethernet card in the machine on which it’s running and the current time (to 100 nanosecond intervals). The algorithm used has been carefully designed to guarantee that identical GUIDs will not be accidentally generated for at least several thousand years. This should guarantee that there won’t be any confusion between interfaces!
Where Are Components Stored
Normally, when you run a program, you’re actually running an executable file. The executable file might call up some other files called dynamic-link libraries (or DLLs) to perform some tasks. A DLL is like an executable file, in that it contains instructions that the computer can run directly. But a DLL differs from an executable file because a DLL cannot be run independently. A DLL really is like a library that can be called up by any executable that’s already running.
Executables can also call upon the functionality contained in other files, such as OLE control extensions (or OCXs). An OCX is essentially a DLL that implements a visual interface. We won’t deal with OCXs in this book.
COM is designed to allow any application or component to call up any other component, no matter where the other component is. This means that COM components can be stored within executable files or as DLLs. When you create a component in Visual Basic or by using the Visual C++ ATL Wizards, you get to choose what type of file you’d like to host the component – a .dll or a .exe file.
There are several factors to consider when choosing which type you want, but broadly speaking an executable offers greater security, while a DLL can give greater performance. This is because an executable will run in a separate process, which means that in order to use the component within the calling application, COM has to spend time passing data back and forth between the application’s process and the component’s process. A DLL-hosted component doesn’t run in a separate process, so for components hosted in DLLs, this overhead is not normally an issue. Because of this, components hosted in DLLs are referred to as in-process components, while those located in executables are referred to as out-of-process components.
One of the slightly confusing aspects of COM is that there are several different names for some of the concepts involved. For example, what we have been referring to as a component, a Visual Basic programmer might call an “externally creatable class module”. To confuse matters even further, C++ programmers may refer to the same thing as a “COM server”, or a “COM object”. We’ll generally stick to the term component here.
Strictly speaking, a COM server is a file (such as a DLL or an EXE) that contains all the executable code for one or more COM components, like this. One corollary of this is that related components can be hosted within the same COM server if necessary.