Skip to content
Mathieu Guindon edited this page Mar 24, 2018 · 17 revisions

Because Rubberduck is basically a COM Add-in, we must deal with registering components that should be visible to either the user's code (in the case of Rubberduck's API) or to the Visual Basic Editor (in the case of Rubberduck's UI, such as tool windows or custom menu). In order for Rubberduck to work, those components must have appropriate entries in the registry.

Because it is shrouded in mystery, it is common to form myths such as believing that regasm.exe is mandatory for registering or that it must be in HKLM hive key. Neither are true. What does trip people up is that COM, being a very big thing and has several related things (e.g. OLE, Automation, COM+, to name a few), there can be varying requirements to get a working COM component depending on how one intend to use the COM component in question. Because we intend to interop with the VBA editor and to be available to the VBA code, we must meet the requirements imposed by VBE, which is implicitly the Automation. Therefore a minimal COM registration will not be acceptable. Furthermore, it is not possible to use a COM component that isn't a part of a type library. Therefore, we must not only describe the COM component but also the type library in order to be acceptable to Automation clients such as Visual Basic.

A recommended reading on what composes a minimum COM registration and additional things we can add is Larry's series of blog posts.

So the takeaway is that we must have the following entries in those sub-branches of the Software\Classes tree.

CLSID = Describes the class ID of a component. This contains all the key data required to activate the component, including the DLL it's located in among other things.

Interface = Describes the interface that a COM component implements. This seems to be opaque but because we are using .NET COM interop, it actually refers to an universal marshaler, which is why we see same GUID {00020424-0000-0000-C000-000000000046} as its ProxyStubClsId32. The COM interop then knows what to do with it and associate with the correct COM class behinds the scene.

TypeLib = Describes the type library that a COM component may be with. Note that simply having a registry entry pointing to the TLB file is not sufficient. All the COM components' CLSID and Interface must in turn contain a TypeLib that refers back to this key.

Record = This subtree is not documented (or at least I could not find an official documentation) but it seems to enumerate all enumerations that are COM-visible. All enumerations have their own GUID, and therefore is used to help find the constant members of the enumeration and this key enables the clients such as Visual Basic to locate the enumeration in the given DLL.

<ProgId> = Provides a registry lookup of CLSID. For example, a registry entry with Rubberduck.AssertClass will have a subkey CLSID with the same GUID as found within the CLSID node. That enables the client such as VBA to locate the actual CLSID with human-friendly name from calls such as CreateObject("Rubberduck.AssertClass"). This is not required for the COM component to function, but we like being friendly to our users, so we include ProgIds.

HKCU and HKLM

Both hive has their Software\Classes. Therefore the same set of registry entries can be written to either simply by changing the root, without any changes to the key, name and value. Obviously, writing to HKCU is nice as this means no admin privilege is required.

However, most of COM lookups may be actually done via HKCR, which is basically a merge of HKLM\Software\Classes and HKCU\Software\Classes, with the entries in HKCU taking precedence. That implies that if there is a COM registration in both place with differing contents, the entries in HKCU will effectively trump those in HKLM.

32/64 bits and registry virtualization

Because we need to support both 32-bit and 64-bit VBA hosts, we need to ensure the same registry entries are written to appropriate places. Because all registry entries end up in Software\Classes, on a 64-bit host, we need to write to Software\Classes\Wow6432Node to make it accessible to the 32-bit host.

A notable item between the 32-bit registry entries and 64-bit entries should be only in the TypeLib because they must point to a specific TLB file. With the Rubberduck project, we build for Any CPU, so we do not need to build both 32-bit and 64-bit versions of the DLL files we generate. However, we must generate both 32-bit TLB file and 64-bit TLB file. For that reason, the TypeLib entries in each must point to the correct TLB. The entry will have a separate win32 and win64 key which should map to the path of the appropriate TLB file.

Clone this wiki locally