Configured CLSID's Explained

advanced topics | home

CLSIDFromProgID returns arbitrary GUID

In COM there is a concept of a configured CLSID. In non-side-by-side world these two are the same. In side-by-side and, sometimes, in DCOM, these two are different. The reason is that you may introduce different COM components with the same GUID by manipulating manifests and activation contexts and side-by-side must be able to handle that. Side-by-side generates a new GUID, the configured CLSID, and adds it to the internal table of CLSIDs. When the program calls CoCreateInstance or a similar API, COM finds the configured GUID and all associated information including the DLL path.

In a standard situation this is not causing any problems:

 
 // Without a manifest the following returns: {88D969E5-F192-11D4-A65F-0040963251E5}
 // With a manifest returns an arbitrary GUID:

 GUID clsid = {0};
 CLSIDFromProgID(L"Msxml2.DOMDocument.5.0", &clsid);

 
 // In either case the following succeeds in creating the COM object:
 
 void* pv = 0;
 CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, &pv);
 

Visual Basic 6 Controls.Add fails

Visual Basic 6 does something hard to explain - it hard codes in the executable the CLSIDs of controls used in Controls.Add() statements even though the only reference is the ProgID. Later, at runtime, it obtains the CLSID using the control's ProgID and then scans the internal table looking for the CLSID. As a result, the following fails:


  Set ctlText = Controls.Add("Nifty.COM.Control", "ctlNifty", Form1)
  
VB6 runtime gets the configured CLSID back from COM and then looks for it in the table which contains the registered CLSID.

This behaviour was discovered too late to be fixed - VB6 was already at EOL. Also, since this behaviour was compiled into the executable, a comprehensive fix would require recompiling all VB6 executables. Many other problems with VB6 were fixed in the VB6 runtime update Service Pack 6 for Visual Basic 6.0.

VB6 is officially supported in Windows 7: Support Statement for Visual Basic 6.0. To work around VB6 idiosyncrasies Microsoft included a number of undocumented hacks in the side-by-side implementation. This can be illustrated by looking at the VB6 runtime manifest C:\Windows\winsxs\Manifests\x86_microsoft-windows-msvbvm60_31bf3856ad364e35_6.1.7600.16385_none_c25a1af6b30d72ee.manifest:


...
 <registryKeys>
   <registryKey keyName="HKEY_CLASSES_ROOT\CLSID\{D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731}" owner="false">
     <registryValue name="" valueType="REG_SZ" value="VBPropertyBag" operationHint="replace" owner="true" />
   </registryKey>
...

For those still supporting and updating VB6 applications, the workaround for the Controls.Add() is to use a control array and the the Load statement.

More information

Support Statement for Visual Basic 6.0
Service Pack 6 for Visual Basic 6.0: Run-Time Redistribution Pack (vbrun60sp6.exe)
Visual Studio 6.0: Working with Control Arrays