VBScripting Solutions: Manipulating COM Objects in the Registry
Some registry keys in the HKEY_CLASSES_ROOT subtree contain information about COM objects. Learn what COM objects are, how you register them, what happens in the registry as a result, and how you create instances of those objects.
February 25, 2001
Last month, I discussed the keys in the HKEY_CLASSES_ROOT subtree that contain information about file classes and system objects. This month, I discuss the keys in the HKEY_CLASSES_ROOT subtree that contain information about COM objects. COM objects are an important underpinning of the Windows system. Let's look at COM objects, how you register them, what happens in the registry as a result, and how you create instances of those objects.
Understanding COM Objects
For COM objects, identity is key. Because COM objects expose a rigorous programming interface, you must be sure of the object you call to avoid errors. Two important identifiers are the globally unique ID (GUID) and the programmatic identifier (ProgID).
GUIDs. Every COM object must have a GUID, a 128-bit hexadecimal value that uniquely identifies the object. Clients use GUIDs to identify COM objects. If you write a COM object, you must generate that object's GUID. You can use Microsoft's guidgen.exe utility to algorithmically generate GUIDs. Some development tools such as Microsoft Visual Studio (VS) and the Windows Script Component Wizard have this utility.
Any interface that a COM object implements also has a 128-bit GUID. A COM object's GUID is called the class ID (CLSID); interface GUIDs are called interface IDs (IIDs). The CLSID identifies the set of functions that the interface defines, so different COM objects can implement the same interface by specifying that interface's IID.
ProgIDs. By design, a COM object is a module of compiled binary code that exposes a collection of interfaces. Any COM object must implement at least the IUnknown interface's functions. The advent of Visual Basic (VB) and scripting environments gave spark to a new subcategory of COM objects: Automation objects—plain COM objects that implement the IDispatch interface, the IDispatchEx interface, or both. Automation objects expose all their functionality through one entry point, which makes the call much easier for the client. However, IDispatch is a generic interface that uses a roundabout method to implement a function. Instead of obtaining a pointer to the function and then accessing that function, the caller invokes an IDispatch method and passes the method the name and arguments of the function it wants to call. IDispatchEx is a child interface of IDispatch that remedies some of IDispatch's shortcomings. These generic interfaces are practical for scripting environments. However, they're less efficient for VB projects because of the late binding between the client and the object.
A COM object can expose its functionality through specific interfaces as well as through the generic interfaces. A COM object that exposes its functionality through both specific and generic interfaces is said to have a dual interface.
A COM object that implements IDispatch or IDispatchEx is also called an automation component. Automation components can have an additional and handy means of identification: the ProgID. A ProgID is any unique string that you want to use as the component's name. Although you can use any string, administrators typically use the format "Library.Server.Version" to help ensure the string's uniqueness.
Although you'll probably always use ProgIDs, keep in mind that ProgIDs are an additional way to identify COM objects, not an alternative way to identify them. All COM objects must have a CLSID. All COM objects can have a ProgID. COM objects that expose dual interfaces typically have ProgIDs.
Registering COM Objects
If you've ever worked with COM objects in any capacity (not just when writing scripts), you probably know that you need to register any COM object you plan to use in your applications in the local machine's system registry. The HKEY_CLASSES_ROOTCLSID key stores all the information about COM objects. Registering a COM object involves creating subkeys under this key. Fortunately, you don't need to write the code that creates the subkeys for a COM object. Typically, you use the Regsvr32 utility. Regsvr32 automatically creates the subkeys by exploiting metadata that the COM object exposes. Thus, you'll probably never have to write the code that creates the subkeys, even if you're registering a Windows Script Components (WSC) object. (See the sidebar "Registering WSC Objects" for information about how to register these objects.) The only situation in which you need to write this code is if you write a COM object in C++ without taking advantage of a specialized framework for writing that COM object.
Regsvr32 is a standard part of Windows. To use this utility, you need only to provide one argument: the pathname of the executable (.dll or .exe file) that provides the COM object. During the registration process, Regsvr32 creates at least two registry subkeys and entries under the HKEY_CLASSES_ROOTCLSID key:
A subkey whose name is the text version of the object's CLSID. The default value of this subkey might contain the ProgID or a description of the component's behavior. A CLSID in the system registry typically takes a format such as {64454F82-F827-11CE-9059-080036F12502}.
A subkey that specifies the name of the executable (.dll or .exe file) that provides the object. If the object is an in-process executable (i.e., a .dll file), the subkey's name is InprocServer32. If the object is a standalone executable (i.e., an .exe file), the subkey's name is LocalServer32. The subkey's default value is the file's pathname. For .dll in-process components, an optional entry, ThreadingModel, declares the threading model that the object supports.
These two subkeys are the minimal configuration. Optional subkeys under the HKEY_CLASSES_ROOTCLSID key include the DefaultIcon, Typelib, Version, Implemented Categories, and ProgID subkeys. (To learn about even more optional subkeys, go to http://msdn.microsoft.com/library/ default.asp?url=/library/psdk/com/reg_6vjt.htm.)
If an object has an icon, Regsvr32 creates the DefaultIcon subkey, whose default value points to that icon. This value is a string (REG_SZ) or an expandable string (REG_EXPAND_SZ) with a pathname and icon index.
Regsvr32 creates the Typelib subkey if an object has a type library. This subkey's default value contains the type library's GUID.
If an object has a version number, Regsvr32 creates the Version subkey and assigns that number to the subkey's default value. However, the version number isn't an integer but rather a string that takes the format "major.minor".
The Implemented Categories subkey stores an object's component categories. A component category informs callers that an object supports a certain functionality (e.g., support for advanced data-binding, Windowless control, ActiveX control). Each category has a GUID. You can find all the registered categories' GUIDs under the HKEY_CLASSES_ROOTComponent Categories key.
A COM object declares its support for a certain category of functionality by creating the HKEY_CLASSES_ROOTCLSIDclsidImplemented Categories subkey, where clsid is the object's CLSID. Under this subkey, Regsvr32 creates as many new nodes as needed to represent all the supported categories.
If an object has a ProgID, Regsvr32 creates the ProgID subkey. The HKEY_CLASSES_ROOTCLSIDProgID subkey's default value contains the object's ProgID. In addition, if an object has a ProgID, the utility creates the HKEY_CLASSES_ROOTprogID key, where progID is the object's ProgID. Under this key, the HKEY_CLASSES_ROOTprogIDCLSID subkey points clients to the object's CLSID. This subkey points to the CLSID because to instantiate a COM object, the code always needs to know the object's CLSID. However, with functions such as VBScript's CreateObject function, you provide the ProgID and not the CLSID. The HKEY_CLASSES_ROOTprogIDCLSID subkey enables the code to obtain the object's CLSID based on the ProgID.
To see examples of the types of information that your registry is storing about the COM objects on your computer, check out the script HKCR_COMInfo.vbs in the Code Library on the Windows Scripting Solutions Web site (http://www.winscriptingsolutions.com). This script prompts you for a COM object's ProgID and returns information about the executable behind the object, its CLSID, and the threading model. Try the script with commonly used ProgIDs, such as WScript.Shell or ADODB.Recordset.
If a COM object is remote, the object's registration needs to extend to the remote machine. The COM extension that enables you to access remote COM objects is Distributed COM (DCOM). To make COM objects accessible throughout a network, you must first use Regsvr32 to register the COM object on the machine on which you want it to reside. You must then use the system-provided Dcomcnfg utility to enable DCOM support and configure the COM object in both the client's and the server's registries.
Creating Instances of COM Objects
After Regsvr32 registers the COM object, the COM Service Control Manager (SCM)—the runtime engine that instantiates COM objects—can identify the object and load its information. You use VBScript's CreateObject function (or a similar function in other scripting languages) to tell the COM SCM which COM object to instantiate. You simply pass CreateObject a string that's the object's ProgID in code such as
Set obj = _CreateObject("ADODB.Recordset")
When this call executes, the VBScript parser uses the COM SCM to locate the specified ProgID (i.e., ADODB.Recordset) in the registry and then find the corresponding CLSID. With the CLSID in hand, the COM SCM creates an instance of the specified COM object.
Next Month
I've now concluded my look at the HKEY_CLASSES_ROOT subtree. Next month, I'll discuss the useful HKEY_CURRENT_USER subtree, which contains information specific to the current user of a machine.
About the Author
You May Also Like