The Component Object Model (COM)COM is a specification that defines rules by which reusable software components, called COM objects, are created. Each object is a collection of interfaces, which themselves are collections of functions -- basically, C++ classes. Using Microsoft's notation, the name of an interface always begins with an "I," much like the way regular class names begin with a "C." Every COM interface is derived from a special base class called IUnknown, which has only three methods: QueryInterface(), AddRef(), and Release(). For you C programmers, a method is simply a member function of a class, and a class is nothing more than a struct whose member functions or variables may not be directly accessible to the user. I know that's not a great definition, but I don't want to get into a lengthy discussion of OOP here! Anyway, back to the three methods of IUnknown: QueryInterface(): This is probably the most important function of a COM object. It is used to retrieve a pointer to the interface you want to work with. In order to get such a pointer, you must know the GUID of the interface. GUID stands for "globally unique identifier" and is a 128-bit value used to identify the interface. GUIDs used in this way are often called interface IDs, or IIDs. When creating a COM object, you can't just make up a GUID. You must use a special program to create one; most Win32 compilers come with such a tool. These programs apply an algorithm that guarantees that no GUID will ever be generated twice. It sounds impossible, but it's not. There are enough combinations that these programs can contain rules by which they generate GUIDs such that no combination will ever be repeated. Let me put it this way. There are six billion people living on this planet. If every one of those people had five million kids, and every one of those kids had five million dogs, and men, women, children and dogs alike sat around all day, every day, generating one GUID per second, it would take them about seventy million years to use up all the combinations. That's probably not going to happen. :) I know of only one dog that sits around generating GUIDs, and it takes him at least ten seconds for each one. AddRef(): COM objects use a variable called a reference count to track their usage. This function simply adds one to the reference count for that particular COM object, and must be called when retrieving a pointer to one of the interfaces contained within that COM object. You almost never do this manually. There are several ways you can obtain an interface pointer, and the ones you'll be using automatically call AddRef(). Release(): When you're finished using an interface pointer, you must release it. This decrements the reference count for the COM object. So when you're writing a program that will be using one or more COM objects, the reference count for each COM object should be at zero when the program ends. Sometimes, if you create an object, and then use that object to create a child object, releasing the parent will also release the child. Since this is not guaranteed, it's usually a good idea to release objects in the reverse order that you created them in. One of the nice things about COM is that its objects can be used with any language, and on any platform. How is this possible? One of the guidelines defining the COM specification states that every COM object must match the binary image that would be generated by a Microsoft Visual C++ compiler. It seems a bit strange to think of it that way, but consider this: once you compile your code, it just becomes binary data. You can't look at a string of 1s and 0s and divine whether it was C++ or Visual Basic before it was compiled, can you? Neither can I. Another feature of COM is that you can recreate or update COM objects without changing or recompiling the programs that use them. The reason this is possible is that COM objects are usually dynamic-link libraries (.DLL files). They aren't compiled into programs that use them; they are linked at run-time. Thus, if a program you write ships with a few COM objects you created, and later on you want to add or change something in one of those COM objects, you simply need to supply users with the new .DLL file. No recompiling the main program is necessary. The new version of the COM object, however, must contain all of the old interfaces and functions. This is to preserve backwards-compatibility. It guarantees that any program created to run with old versions of COM objects will function exactly the same if it's using new versions of those objects. Since DirectX follows the COM specification, the same rules apply. A program developed with DirectX 5.0 will work just fine if the user has DirectX 7.0 installed on his computer. Cool, hey? |
|