On each host system, COM uses the system registry (also called the registration database) to store relevant information about components according to their CLSIDs. In the chapters ahead, we'll see the entries necessary to map a CLSID to the server that implements a component or to the type library that describes the component and its interfaces. Anytime you need to associate any information with any GUID for any reason, you'll use the registry. Such information is then available to everything else in the system without requiring the instantiation of any component. This does, of course, require some standards.
In the registry of a system in which OLE is installed, there will be a key called CLSID directly off the root key known as HKEY_CLASSES_ROOT. If you run the REGEDT32.EXE program with the Win32 SDK, you'll see this set of entries in a window with the caption "HKEY_CLASSES_ROOT on Local Machine." The top-level key (folder) shown in the window will be labeled "HKEY_CLASSES_ROOT," and there will be a subkey (subfolder) labeled "CLSID." Under this subkey, you'll find all the information about component classes.
The primary entry you must make for a CLSID is a subkey under the CLSID key. Your subkey name is your CLSID spelled in hex digits within braces—such as {42754580-16b7-11ce-80eb-00aa003d7352}—where the value of that subkey is the human-readable name that you want to associate with the CLSID. (All characters are acceptable in the name, including spaces and punctuation.) This provides a pretty name that can be displayed by a client without scaring off the end user. The documentation convention for describing a registry entry such as this is to use a backslash for the root. Each entry below the root is indented and written as a "key = value" pair. (The "= value" can be omitted.) So the entry described here is written as follows:
\
CLSID
{42754580-16b7-11ce-80eb-00aa003d7352} = Acme Component 3.0
You might also want to associate your CLSID with what is called a programmatic identifier, or ProgID, which effectively (but less precisely) identifies the same class. A ProgID, which is not considered something that an end user should see, is a text string4 without spaces that can be used in programming contexts where referring to the ugly CLSID string isn't appropriate. For example, you use ProgIDs to identify an object class in Visual Basic instead of the raw CLSID because Visual Basic doesn't have a way to define the same GUID structure and can't read C/C++ header files in order to pull in symbolic names. The ProgID is thus an alternative language-independent symbolic name.
The standard ProgID format is <Vendor>.<Component>.<Version>, such as Microsoft.Chart.5 or Lotus.AmiProDocument.4.2. This format is reasonably unique, and if everyone follows it there will generally not be a collision. (The trademark lawyers ensure this.) There is also the VersionIndependentProgID, which has the same format without the version number. Both the ProgID and the VersionIndependentProgID can be registered, with a human-readable name as a value, below the root key. You should include a "CurVer = <ProgID>" entry under VersionIndependentProgID to provide a convenient mapping between ProgID and VersionIndependentProgID, and then you should include a "CLSID = <{CLSID}>" entry under ProgID to map it to the CLSID, as shown at the top of the following page.
\
Acme.Component.3 = Acme Component Version 3.0
CLSID = {42754580-16b7-11ce-80eb-00aa003d7352}
Acme.Component = Acme Component
CurVer = Acme.Component.3
The VersionIndependentProgID is thus mapped to the ProgID, which is mapped to the CLSID. You will also want to map the CLSID itself to both ProgIDs, using additional entries such as these:
\
CLSID
{42754580-16b7-11ce-80eb-00aa003d7352} = Acme Component 3.0
ProgID = Acme.Component.3
VersionIndependentProgID = Acme.Component
OLE provides functions to look up a ProgID from a CLSID and vice versa using registry information so that you don't have to consult the registry directly:
Function | Purpose |
ProgIDFromCLSID | Returns the ProgID associated with a given CLSID |
CLSIDFromProgID | Returns the CLSID associated with a given ProgID |
To create registry entries, you can either write code using the Reg* Win32 APIs (which is a pain) or create a REG file and simply run it to merge its entries with the registry. The file below will create all the entries that were shown above:
REGEDIT
HKEY_CLASSES_ROOT\Acme.Component.3 = Acme Component Version 3.0
HKEY_CLASSES_ROOT\Acme.Component.3\CLSID = {42754580-16b7-11ce-80eb-00aa003d7352}
HKEY_CLASSES_ROOT\Acme.Component = Acme Component
HKEY_CLASSES_ROOT\Acme.Component\CurVer = Acme.Component.3
HKEY_CLASSES_ROOT\CLSID\{42754580-16b7-11ce-80eb-00aa003d7352} = Acme Component 3.0
HKEY_CLASSES_ROOT\CLSID\{42754580-16b7-11ce-80eb-00aa003d7352}\ProgID = Acme.Component.3
HKEY_CLASSES_ROOT\CLSID\{42754580-16b7-11ce-80eb-00aa003d7352}\VersionIndependentProgID = Acme.Component
You can see that each backslash represents another level in the registration hierarchy. Also note that the spaces around the equal signs are used to separate the key name (which cannot have spaces) from the value (which can have spaces).
As you might have guessed, not all components and objects need to have a CLSID because there are other ways to uniquely identify them. In general, only those custom components that want to be created through a function such as CoCreateInstance require a CLSID. This includes, but is not limited to, all compound document content objects, all OLE Controls, and any OLE Automation objects providing a service (as opposed to those that just implement IDispatch for some other reason). These require additional entries to identify the component server, as we'll see in Chapter 5. In addition, the registry is the only way to associate an object class with type information without needing an already running instance of the object; if you want to make such information available, there are entries to map a CLSID to a type library, as described in Chapter 3. The registry is also used to associate an interface with its marshaling proxy and stub implementations, which are packaged in a component with a CLSID. Outside of these uses, a CLSID is totally unnecessary, especially for objects that are created internally within a component, such as an event sink, a client site in a compound document container, or a portion of a filename with a moniker.
4 A ProgID can contain DBCS characters but because end users never see a ProgID it is rather pointless to include these characters. |