This is a three parts article explaining basics and implementation of COM technology. Part 1 gives a basic introduction to COM architecture. Part 2 shows how to create your own COM server and finally Part 3 shows how to create the COM client and use the COM server created in Part 2. This approach is general and basically, this is the way to interact with any other COM servers also.
Background
Component Object Model (COM) is a not a new technology, in fact, it is a very old one. Microsoft introduced it in 1993. Even though it is an old technology, it is a very much celebrated one. There are literally millions of applications based on COM technology and a huge amount of money has been invested on it worldwide. Today, .NET technology, almost replaces COM. Despite this, there are already many COM controls and as you program for Windows, you will encounter the necessity to integrate your application with these COM controls. Possibly, you may require to write your own COM controls/server also.
Introduction
So what is COM ?
COM is a binary standard that defines a way for software objects, developed in different languages or operating on different platforms, to communicate. A COM component is a resuable software object that conforms to COM specifications.
COM objects allow you to construct an application comprising a set of distinct cooperating components. One benefit of using COM objects is that they make interoperability available, irrespective of where the binary object is physically located. An imporant aspect of COM objects is that a program may attach dynamically to the object during execution.
For example, an application hosted in an executable file may link dynamically to a COM component hosted in a DLL. Because the component and executable are dynamically linked, they do not need to reside in the same location. To dynamically link to a binary object during execution, a program and the operating system cooperate to locate the object. COM defines all elements that both you and the operating system use in cooperation to ensure that the dynamic linking process works correctly.
How do the look like and how to interact?
COM objects are implemented as .dll or .exe files. Every COM object that resides on your system must be registered with the Windows operating system. Registration information appears in the Windows registry. In the registry, you find a class identifier (ClassID) that identifies the object uniquely across all computers. The ClassID is a specially formatted globally unique identifier, or GUID.
When your client wants to link dynamically to a registered COM object, the client program uses the ClassID to identify the binary object. The COM run-time libraries, an integral component of the Windows operating system, provide the means for clients to locate and instantiate COM objects.
Once the COM libraries receive a ClassID, they search the HKEY_CLASSES_ROOT portion of the registry in an attempt to find the location of the COM object that owns that ClassID. If the search is successful, the COM libraries create an instance of the object and return a pointer to the object’s interface. The client uses this pointer to call the methods that the object provides. Otherwise, an error is reported to the client. An application will typically interact with this dynamically linked binary object by executing methods listed in its interface pointer. If the object needs to initiate interaction with your client program, you register event handler methods with the object. Under appropriate and well-defined conditions, the object fires events that are processed by these handler methods.
One of the features of COM is location transparency. Client applications can be written without concern as to whether the objects used run within their process, in a different process on the same computer, or in a process on a separate computer.
COM Interfaces
COM is heavily interface driven. You COM object provides access to its services through one or more interfaces. A COM interface is a logical grouping of related methods identified by a GUID, known as an Interface Identified (IID). COM components are often described in terms of the client/server model, wherein a COM server is a component that provides services to client programs through the methods it exposes. Using this model, an interface can be understood as a description of the services provided by a component.
You gain access to the methods provided by the interface by obtaining a pointer to the interface, which references a table of function pointers known as the “vtable”. Each function pointer in the vtable enables you to access a single method provided by the interface.
An interface is a logically separate entity from the component that implements the component. In other words, the same interface can be implemented by many different components. An interface is analogous to a C++ abstract class definition. The identity of an interface is established by its unique IID. Once you publish your interface specification to the world, you are guaranteeing to anyone who might want to use or implement your interface that it will not change. The number and order of the methods, and the data types of the arguments and return values, are guaranteed to remain the same. If you want to add or alter methods, you must define a new interface with a different IID.
The fact that an interface is obtained as a pointer to a function table (the vtable), would seem to imply that a COM object could provide only methods to client applications. However, many languages that support COM (Microsoft Visual Basic, for example) support the notion of properties—public data members of components that are analogous to the member variables of a C++ class. Components written in C++ implement properties as pairs of methods used to set and get the value of encapsulated class data.
GUID
GUIDs are 128-bit numeric identifiers that uniquely distinguish each COM object and the specific interfaces supported by COM objects. GUIDs are guaranteed to be unique across the world and to remain unique for a very long time. You use the Windows command-line utility UUIDGEN.EXE (or the graphical user-interface version GUIDGEN.EXE) to generate GUIDs for your components and interfaces.
A detailed characterization of a GUID appears below.
A GUID actually exists in two formats: string and numeric. A string format appears in various locations in the registry. Numeric representations of GUIDs are necessary when using the GUID within client applications and within the actual COM object implementation.
When you use the numeric representation within your COM object or within C++ client code, you declare a variable and use a specific macro to initialize the variable to the associated numeric value. The macro that you use is named DEFINE_GUID and appears in the header file initguid.h. Typically, the variable name that you use begins with either the prefix CLSID or IID. These prefixes indicate whether the GUID refers to a COM object or to an interface supported by a COM object.
COM Registry Entries
When you install a COM object onto a computer, you must register the object by creating entries in the computer’s registry.
Figure below illustrates the registry entries required for a typical COM object.
To register your COM object, you create entries under the HKEY_CLASSES_ ROOT subtree, under the predefined CLSID key. These entries enable the COM libraries to locate your COM object and load it into memory. Beneath the CLSID key, you type a subkey that is the string form of your CLSID COM object. Beneath this subkey, you attach the subkey that provides COM with the path to the component server, as shown here:
HKEY_CLASSES_ROOT\CLSID\{64CE33A0-6B03-11d3-9352-0080C7FA0C3E}\
InprocServer32 = c:\Encoder\debug\Encoder.dll
|
The name of the subkey—InprocServer32—indicates that the component server is a DLL on the local computer.
Immediately beneath HKEY_CLASSES_ROOT, you can provide a key value representing a string name for your COM object. This string name is a version-independent programmatic identifier (ProgID). Associated with this string name, you type a subkey explicitly named CLSID whose value indicates the GUID for your COM object in its string format. A path representation for this entry looks like this:
HKEY_CLASSES_ROOT\Encoder\CLSID = {64CE33A0-6B03-11d3-9352-0080C7FA0C3E}
|
By using a function named CLSIDFromProgID(), a client application can retrieve the CLSID from the ProgID. By providing the ProgID, you enable a client application developer to create an instance of your COM object without having to go through the error-prone process of typing a CLSID into the source code. Visual Basic client code will always specify COM objects as ProgIDs, so you will need to register a ProgID if you are intending to use your objects with non-C++ clients.
Summary
COM allows dynamic linking of binary software components that can reside on a local computer or on a computer across a network. The COM run-time library uses registry entries to locate and to load a COM object. Every COM object supports the IUnknown interface and additional component-specific interfaces. Each interface is a collection of one or more methods. Separate GUIDs identify the COM object and every interface exposed by the object. Within your class implementation you provide an object known as a class factory that creates an instance of your COM object.
Next: In Part 2, I will explain step by step, how to create your own COM Server. Many aspects described here in words, will be clearly visible. Part 3 will show the client part.
Credit: This explanation of COM architecture i.e. Part 1 has been taked from the book – Desktop Applications with Microsoft Visual C++ 6.0 MCSD Training Kit.
Other Links:
1. http://en.wikipedia.org/wiki/Component_Object_Model
2. http://www.codeproject.com/KB/COM/comintro.aspx
3. http://www.codeproject.com/KB/COM/#COM/DCOM/COM+%20-%20Beginners
Filed under: C plus plus, COM | 2 Comments
Tags: Component Object Model (COM), Reusable software component, ClassID, CLSID, GUID, IID, Interface, vtable, COM Registry Entry architecture, COM Programming


2 Responses to “Working with COM : Part 1 – Basics”