i need write the code that runs when DllRegisterServer is called. i.e. when someone calls:
regsvr32 myActiveX.ocx
i'm trying to find the definitive list of required registry entries (rather than just what i can cobble together by spellunking through the registry).
So far my expeditions have found:
HKEY_CLASSES_ROOT
\MyCoolLibrary.MyCoolControl
\Clsid
(default) = "{myClassId}"
\CLSID
\{myClassId}
\Control
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
\MiscStatus
\1
(default) = 205201
\ProgID
(default) = "MyCoolLibrary.MyCoolControl"
\ToolboxBitmap32
(default) = "c:\foo\myActiveX.ocx,1"
\TypeLib
(default) = "{myTypeLibraryGuid}"
\Verb
\0
(default) = "Properties,0,2"
\Version
(default) = "1.0"
\TypeLib
\{myTypeLibraryGuid}
\1.0
(default) = "MyCoolLibrary.MyCoolControl"
Now, the concerns:
- what does the Control folder contain? Is it's presence indicate a control?
- what's a MiscStatus of 205201 do? What would 205202 do instead?
- What's the verb "Properties,0,2"? Where's "Properties,0,0" and "Properties,0,1"?
In other words, i'm looking for the docs.
What i know so far. COM creates an object based on it's clsid. This is a guid that uniquely identifies that class.
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
That class is then used to create objects. COM now needs to know where the DLL is that holds that COM Object. In my particular case, the "server" that exposes the COM object is a DLL, and will be "in process". We then point COM to that "in-process" dll by adding:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
COM also needs to know the threading model that the COM server object supports. The simplest, most common, and the one used in this example is the "Apartment" threading model:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
Next is the ProgID. This is similar to how DNS is used to turn a friendly name into an IP. Here we turn a friendly name "MyCoolLibrary.MyCoolControl"
into the ugly clsid "{AE8530CF-D204-4877-9CAB-F052BF1F661F}"
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
HKEY_CLASSES_ROOT
\MyCoolLibrary.MyCoolControl
\Clsid
(default) = "{AE8530CF-D204-4877-9CAB-F052BF1F661F}"
Now someone can ask for
MyCoolLibrary.MyCoolControl
and COM can turn that into the ClassID
{AE8530CF-D204-4877-9CAB-F052BF1F661F}
Once COM has the clasid, it can then look in the registry under HKCR\Clsid\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
to find the real information.
For fun, the ProgID is added to the Clsid section, just so people can have some idea what this class is:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
\ProgID
(default) = "MyCoolLibrary.MyCoolControl"
HKEY_CLASSES_ROOT
\MyCoolLibrary.MyCoolControl
\Clsid
(default) = "{AE8530CF-D204-4877-9CAB-F052BF1F661F}"
Next is the type library. This is mostly unimportant for anything in-process, but if the COM object is in another "apartment", then function parameters need to be marshalled. COM does this automatically for you if it has a type library that defines all the classes methods.
The clsid section is pointed to the appropriate type library with the addition of a TypeLib key:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
\ProgID
(default) = "MyCoolLibrary.MyCoolControl"
\TypeLib
(default) = "{17A5A3D4-439C-4C2A-8AB4-749B7771CDE1}"
HKEY_CLASSES_ROOT
\MyCoolLibrary.MyCoolControl
\Clsid
(default) = "{AE8530CF-D204-4877-9CAB-F052BF1F661F}"
Information about this type library is also stored in the registry, but adding these keys is done for us with a call to RegisterTypeLib. But it will add keys for us similar to:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\InprocServer32
(default) = "c:\foo\myActiveX.ocx"
ThreadingModel = "Apartment"
\ProgID
(default) = "MyCoolLibrary.MyCoolControl"
\TypeLib
(default) = "{17A5A3D4-439C-4C2A-8AB4-749B7771CDE1}"
HKEY_CLASSES_ROOT
\MyCoolLibrary.MyCoolControl
\Clsid
(default) = "{AE8530CF-D204-4877-9CAB-F052BF1F661F}"
HKEY_CLASSES_ROOT
\TypeLib
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\1.0
(default) = "My Cool ActiveX Library"
...
Now we get into the tricky stuff, stuff that is needed to hopefully make an ActiveX control work.
An MSDN article states that you must add a dummy Programmable key to indicate that it is an ActiveX control:
HKEY_CLASSES_ROOT
\Clsid
\{AE8530CF-D204-4877-9CAB-F052BF1F661F}
\Programmable
But this MSDN Library page says the keyword is Control, and not Programmable - and there is no Programmable key.
But that doesn't stop some ActiveX's from using Control, some using Programmable, and some using both.
i cannot find anything mentioning anything else being required.
So, can anyone find some definitive documentation?
Larry Osterman provides a good jumping-off point:
A large part of the "cargo cult"
nature of this is the fact that there
are a bewildering set of registry
settings that can be set for COM
objects, and it's not clear which, if
any apply. So I'm attempting to lay
out a series of articles that can help
people determine what they need to
set.
-- What registry entries are needed to register a COM object.
Summary: it depends on what scenarios you need your object to be used in. The most basic, absolutely-necessary settings are the default value and ThreadingModel in HKEY_CLASSES_ROOT\CLSID\<clsid>\
, but most of the time you'll want ProgIDs and AppIDs as well.
Find/borrow/steal a copy of Inside OLE 2, by Kraig Brockenschmidt. It's old like the world (and dates me as well :-))
Here's also a high-level overview of the registry entries mentioned above.
Read Larry Osterman's blog post for more pointers.
Look at the MSDN ActiveX samples.
Also, you are missing entries under the HKCR\Interfaces for all custom interfaces and event interfaces your control implements.
It's not exhaustive, but try this MS knowledge base article.
Also, Larry Osterman has a useful blog post here.
It occurs to me that another approach would be to use a tool like RegMon and directly monitor what registry changes are made when your DllRegisterServer method is called.
By all means, go with the Larry Osterman article linked.
Additionally, a good starting point are the ATL registrar scripts generated by the MSVC ATL COM object wizard. You can play with different options and see how they affect the output.
Side note if you want to see experimentally what keys are created: use Sysinternals' Process Monitor, it will capture in real time the activity on the registry when you register the control.
Are you working on a 64 bit OS?
If so, instead of writing to
HKEY_CLASSES_ROOT\CLSID\
you should write to
HKEY_CLASSES_ROOT\Wow6432Node\CLSID\