COM Fundamentals

3. Gloabally Unique Identifiers (GUIDs)

COM uses globally unique identifiers¡ª128-bit integers that are guaranteed to be unique in the world across space and time¡ªto identify every interface and every component object class. These globally unique identifiers are UUIDs (universally unique IDs) as defined by the Open Software Foundation's Distributed Computing Environment. Human-readable names are assigned only for convenience and are locally scoped. This helps ensure that COM components do not accidentally connect to "the wrong" component, interface, or method, even in networks with millions of component objects. CLSIDs are GUIDs that refer to component object classes, and IID are GUIDs that refer to interfaces. Microsoft supplies a tool (uuidgen) that automatically generates GUIDs. Additionally, the CoCreateGuid function is part of the COM API. Thus, developers create their own GUIDs when they develop component objects and custom interfaces. Through the use of defines, developers don't need to be exposed to the actual 128-bit GUID. For those who want to see real GUIDs in all their glory, the example below shows two GUIDs. CLSID_PHONEBOOK is a component object class that gives users lookup access to a phone book. IID_ILOOKUP is a custom interface implemented by the PhoneBook class that accesses the phonebook's database:

DEFINE_GUID(CLSID_PHONEBOOK, 0xc4910d70, 0xba7d, 0x11cd, 0x94, 0xe8, 0x08, 0x00, 0x17, 0x01, 0xa8, 0xa3);

DEFINE_GUID(IID_ILOOKUP, 0xc4910d71, 0xba7d, 0x11cd, 0x94, 0xe8, 0x08, 0x00, 0x17, 0x01, 0xa8, 0xa3);

The GUIDs are embedded in the component binary itself and are used by the COM system dynamically at bind time to ensure that no false connections are made between components.

IUnknown

COM defines one special interface, IUnknown, to implement some essential functionality. All component objects are required to implement the IUnknown interface, and conveniently, all other COM and OLE interfaces derive from IUnknown. IUnknown has three methods: QueryInterface, AddRef, and Release. In C++ syntax, IUnknown looks like this:

interface IUnknown {
   virtual   HRESULT   QueryInterface(IID& iid, void** ppvObj) = 0;
   virtual   ULONG   AddRef() = 0;
   virtual   ULONG   Release() = 0;
   }

AddRef and Release are simple reference counting methods. A component object's AddRef method is called when another component object is using the interface; the component object's Release method is called when the other component no longer requires use of that interface. While the component object's reference count is nonzero, it must remain in memory; when the reference count becomes zero, the component object can safely unload itself because no other components hold references to it.

QueryInterface is the mechanism that allows clients to dynamically discover (at run time) whether or not an interface is supported by a component object; at the same time, it is the mechanism that a client uses to get an interface pointer from a component object. When an application wants to use some function of a component object, it calls that object's QueryInterface, requesting a pointer to the interface that implements the desired function. If the component object supports that interface, it will return the appropriate interface pointer and a success code. If the component object doesn't support the requested interface, then it will return an error value. The application will then examine the return code; if successful, it will use the interface pointer to access the desired method. If the QueryInterface failed, the application will take some other action, letting the user know that the desired method is not available.