How to clean unused COM registration from the registry? - com

I got some COM components (DLLs) registered on my machine, however the DLLs associated these COM components were deleted (so I can't use regsrv32). How can I clean up my registry of these old COM components. I wonder if there is a tool that list what's registered and allow me to remove components I know are no longer used.

Easy way - oleview.exe from Win SDK - look to Registry tab.
on my machine it is here: "C:\Program Files (x86)\Windows Kits\8.0\bin\x64\oleview.exe" It's part of Visual Studio installation. Or you can download it separately for free: Win7 SDK It will show you all registry entries related to registered component - then delete them manually with regedit.exe
manually (you can register COM class not only as the local machine level but also at the user level, and so you should be very careful as the HKCR is a merged view of HKLM\Software\Classes key and HKCU\Software\Classes key.):
Search registry by name of your DLL in HKCR (for example: HKEY_CLASSES_ROOT\CLSID{9B208FF8-F6B0-4290-94DE-7A4E857D8C4A}\InprocServer32) where GUID will correspond to your coclass CLSID. let it be GUID_A.
Then search by GUID_A and delete other entries (they are optional):
ProgID like HKEY_CLASSES_ROOT\YourServerName.YourCoclassName\CLSID = {GUID_A},
TypeLib in HKEY_CLASSES_ROOT\TypeLib\ {GUID_A}.
HKEY_CLASSES_ROOT\AppID\ {APPIDGUID} where {APPIDGUID} can be extracted from CLSID entry in bullet step 1.
HKEY_CLASSES_ROOT\Interface{IID}. Used for marshalable interface - To find it you can use CLSID of inproc server (another) that implements proxy, stub for this interface. I hope your COM server has no marshalable interfaces.

Related

Several short questions about COM .net assemblies, regasm, dll, tlb and guids

All question are related to a .net project dll in .net framework 2.0 that exposes itself as COM.
1) If we don't specify any GUIDs in the source code (typelib, classes, interfaces) who is generating the GUIDs? The compiler or regasm?
2) The GUIDs values exists in the dll, in the tlb or in both files?
3) Any developer with the same source code would generate the very same GUIDs independently on the machine where she builds or run regasm?
4) If I run regasm passing existing dll and tlb files, what happens If the dll and the tlb doesn't match? Regasm regenerate the tlb file with uptodate elements and GUIDs? Or it registers the TypeLib with the current tlb file?
5) What is the point of running regasm with dll and tlb parameters set?
Tlb file is part of what you deploy or it is best practice to only deploy the dll and let regasm generate the tlb on the fly?
6) And last question, is tlb really required? What is the point of having a tlb file? Is not all the information already in the registry? What extra info it provides?
7) When unregistering with regasm, what we need to provide? The dll? The Tlb? Both? What happens if dll (or tlb) doesn't match with existing reg entries? If already registered with tlb option but I run regasm unregister with dll only it would delete the TypeLyb entry too?
8) Regarding bitness, regasm will always generate entries under SysWow64 too? The regasm under Framework64 do the same as the one under Framework?
A type library is the exact equivalent of .NET metadata. It is most of all useful to the client programmer, it makes the compiler and the IDE smart about your library. Providing auto-completion and syntax checking so the odds of a mismatch between his code and yours are minimal. The registration step is necessary so your files can be found back. The type library is normally embedded as a resource in the DLL itself, like .NET metadata, but the .NET build model does not make that easy to do. The client compiler uses the type library info to generate the appropriate COM calls. Guids are a big deal because that is what the client compiler needs to use, identifier names play no role. There is a way to use "late binding" using names, the exact equivalent of Reflection in .NET, but that does not involve a type library.
who is generating the GUIDs?
The CLR does. Every .NET interface or class has one, regardless if it is [ComVisible(true)]. Exposed also through the Type.GUID property. If you didn't use the [Guid] attribute on the type then it runs an algorithm to generate the Guid that uses the type declaration as input. Or in other words, if you make any changes to the type then you can be sure that the Guid will have a different value. Which is the basic reason you should never use the [Guid] attribute, unless you have to create an exact drop-in replacement and cannot recompile client code. The TLBID comes from the AssemblyInfo.cs file that was auto-generated when you created the project.
in the dll, in the tlb or in both files?
It only exists in the DLL when you used the [Guid] attribute, but normally it is generated at runtime as explained above. It is always present in the type library, that's how the client compiler knows to create an object of your class and use its interface(s).
would generate the very same GUIDs
Yes, only the type declaration plays a role.
If I run regasm passing existing dll and tlb files
Regasm can only create a type library, as requested with its /tlb option, it cannot take an existing one. It otherwise does the exact same thing as Tlbexp.exe does, use Reflection to enumerate the types in the assembly to find the [ComVisible(true)] ones and generate the matching type library declaration. The extra thing it does is write the registry key for the type library to HKLM/Software/Classes/Typelib. So the client IDE can find it back.
What is the point of running regasm with dll and tlb parameters set?
No real idea with "dll parameter" might mean. As noted above, use /tlb to generate the type library. Whether or not you deploy the type library depends on its usage, if you don't also provide the client code then you should always deploy it so the client programmer can use it. Other usage of the type library is the subject of this post. If you're not sure how the client programmer is going to use your code then always deploy.
Is not all the information already in the registry?
What's in the registry is limited, only enough info to find the type library file back. The description of your interfaces, their method signatures, guids and the CLSID that the factory function needs is in the type library.
When unregistering with regasm, what we need to provide?
Exact same thing as registering it, you only add /unregister. You must also provide /tlb if you used it previously so the TypeLib registry key can be deleted. It can be pretty important to automate this while you are busy developing and testing the library, since the guids are normally auto-generated you can produce a lot of garbage in the registry. As well as ugly head-scratching when you forget to run Regasm. Project > Properties > Build tab, "Register for COM interop" checkbox. But with the downside that you have to run VS elevated so it can write to the registry.
regasm will always generate entries under SysWow64 too?
SysWow64 plays no role, do always avoid deploying to c:\windows. But yes, bitness does matter, the registry is structured so a 64-bit app cannot accidentally create an object in a 32-bit library and die on an ugly exception. And the other way around. A 32-bit client app will read registry keys from HKLM/Software/WOW6432Node, you only get your registry keys there is you used the 32-bit version of Regasm. Notable perhaps is that it is usually fine to run both flavors of Regasm, given that C# code can run on any platform.

WIX: COM registration fails when installing COM dll into another folder

I am using heat to harvest the COM dll and tlb files (let's call them MyLib.*, developed in VB.NET) to do the COM registration. Everything was working fine, when I install MyLib.dll and MyLib.tlb into my application's installation folder, i.e., INSTALLDIR. However, since we want to allow different versions of our SW to be installed on the same machine, and if they are using the same version of COM component, only one copy of the dll (I think each version of our SW should have its own tlb, please correct me if I am wrong) should be installed, we now want to install MyLib.dll into another folder, specifically PROGRAM_FILES\Common Files\SHARED_FOLDER_NAME, so now if one version of our SW is uninstalled, the MyLib.dll will not be removed and can still be used by other versions.
But here comes the problem: my COM registration is just simply not working any more after I install this dll into this another folder, and it keeps saying that can't find file specified when I am calling the COM function which indicates registration failure. In the WIX installer project, everything is the same except this folder for MyLib.dll.
Here is the registry structure after installation:
Firstly I have HKCR\CLSID{MYCLSIDs}, each of them represents one of my COM class. in the sub-key named "InprocServer32", I have Assembly, Class, CodeBase, RuntimeVersion, threadingModel. And the CodeBase is either common file folder (not working) or MyApp's installation folder(working), which is the different locations I put the dll. I thought there would be another sub-key TypeLib under {MYCLSIDs}, since Access only sees the TypeLib and I think there should be some link from the TypeLib to the actual dll, however, at both cases this sub-key is missing but in the second case it is still working. Is there a problem of it?
Secondly I have HKLM\Software\Classes\CLSID{MYCLSIDs}, these keys are of course the same structure as described above.
Thirdly, the HKCR{MYPROGIDs}, these are just ProgIDs of my classes
Fourthly, HKCR\Typelib{LibID}, which includes the information from tlb file, and this ID is from the Assembly GUID of COM component project.
Finally, the HKEY_CLASSES_ROOT\Interface{InterfaceID}, there is sub-keys named ProxyStubClsid32 with value {00020424-0000-0000-C000-000000000046}, and the one named TypeLib and the value is my LibID.
As I mentioned, the only difference is the CodeBase, which stores where MyLib.dll is located. In order to verify that, I did two tests: after I install MyLib.dll into the shared folder, the COM calling fails. But if I replace all the CodeBase values for SHARED_FOLDER\MyLib.dll to INSTALLDIR\MyLib.dll, and copy MyLib.dll into INSTALLDIR, it actually works. Vise versa, after I install MyLib.dll into INSTALLDIR(in which case COM is working), I change the CodeBase values from INSTALLDIR\MyLib.dll to SHARED_FOLDER\MyLib.dll, and make a copy to SHARED_FOLDER, this time it fails. So it seems that it is exactly the installation location's problem, which is the opposite to my understanding of COM. And I don't think there is a permission issue for the SHARED_FOLDER(I could be wrong) since it is in a folder that my installer creates.
Please help, thanks!
It turned out that MyLib.dll is using some other libraries, which are still installed in the MyApp installation folder. And so in that case that MyLib.dll is installed in the shared folder, it tries to find those libraries in the same libraries, which of course fails. When I install those libraries in the shared folder too, it is working.
BTW I found fulogvw.exe very helpful when tracking down the assembly loading problem. For example in my case in the failed log it says can't load file xxx.dll in SHARED_FOLDER, the xxx.dll is some library that MyLib.dll is using, and I had no idea that MyLib.dll needs it until I see the log.

How do I properly register the Type Library of A VB.NET COM+ Component?

I am looking to upgrade legacy VB6 COM+ components to VB.NET components. I have seemingly upgraded one already, called EventPackage, which has one class, IEventListener. Another, TradeOrders, Implements EventPackage.IEventListener. When attempting to build TradeOrders, I get the following Errors/Warnings;
Cannot load type library for reference "EventPackage". Library not registered. (Exception from HRESULT: 0x8002801D (TYPE_E_LIBNOTREGISTERED))
The referenced component 'EventPackage' could not be found.
Type 'EventPackage.IEventListener' is not defined.
In the .vbproj, I notice this reference
<COMReference Include="EventPackage">
<Guid>{0D76C094-21A6-4E04-802B-6E539F7102D7}</Guid>
<Lcid>0</Lcid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<WrapperTool>tlbimp</WrapperTool>
</COMReference>
When I search the registry for this Guid, I find nothing. When using GUIDs for similar COM+ objects, I find them in HKEY_CLASSES_ROOT\CLSID\{...}\TypeLib ("..." being the GUID of the other component). When I go to the registry key name corresponding to EventPackage.IEventListener, I find that there is no \TypeLib subkey. As you might suspect, searching the reg for "0D76C094-21A6-4E04-802B-6E539F7102D7" yields no results.
So I know this must be a registry problem, But I have tried seemingly every google result I have found. I have tried Regasm and regsvcs .exe's to no avail. Many pages just tell me that dragging the dll to the COM+ manager should automatically register the component.
So how do I register the Type library?
Details on how I made EventPackage COM+ component
Ran the VB6->VB.NET wizard
Then I added some lines to the assemblyinfo.vb file
added Imports System.EnterpriseServices
added Imports System.EnterpriseServices
Imports System.Data.SqlClient
<Assembly: CLSCompliant(True)>
<Assembly: AssemblyKeyFileAttribute("...")> for a strong name
<Assembly: Guid("...")> (Where "..." is the COM+ CLSID of the old component)
I added the following to the class file IEventListener.VB
Imports System.EnterpriseServices
<ComClass("...")> _ (Where ... is the proper COM+ CLSID, that is the only argument)
Inherits ServicedComponent
changed the ID made by the Conversion wizard to the proper value (from <System.Runtime.InteropServices.ProgId("IEventListener_NET.IEventListener)> to <System.Runtime.InteropServices.ProgId("EventPackage.IEventListener")> _
Then I dragged the DLL into the COM+ manager in the proper COM+ application (although, the "Path" is not specified and only says mscoree.dll)
I had that dam error (0x8002801D (TYPE_E_LIBNOTREGISTERED)) yesterday, it drove me crazy: VSTO Add-ins, COMAddIns and RequestComAddInAutomationService
It might be a red-herring but my answer has similar details about reg keys not existing and etc:
Right click on Visual Studio (2010) > Run As Administrator > Open Project > Compile!
The console command "regsvr32 mydll.dll" will register your COM component. You should be able then to find the guid under HKEY_CLASSES_ROOT\CLASSID then, under which the InprocServer32 folder will have the path to your dll. This is how COM looks up the dll.
I think that the problem here is that you haven't generated a type library for your .NET component. I know you said you used regasm - but did you use the right command line?
Start Menu => Programs => Microsoft .NET Framework SDK vX.Y => SDK Command Prompt.
In this command line line, type: regasm /tlb:Mydll.dll

Type Library HELPDIR wrong

I'm developing a registered COM type library. When I build it, Visual Studio automatically registers the library. I can view the type library in OleView.
I have two branches of this library, in separate directories, which is causing the problem: the HELPDIR is pointing at the wrong branch. My registry looks like this:
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}]
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}\1.0]
#="My Type Library"
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}\1.0\0]
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}\1.0\0\win32]
#="c:\\path\\right_dir\\mylib.dll"
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}\1.0\FLAGS]
#="0"
[HKEY_CLASSES_ROOT\TypeLib\{6C964648-D0B3-4c8a-B7D5-53D176CBCC68}\1.0\HELPDIR]
#="c:\\path\\wrong_dir"
How do I get Visual Studio to correct the HELPDIR path when I build and register my library?
I used regsvr32 to unregister and then re-register the type library. When I unregistered, the registry keys were removed. Then when I registered again the correct values were added.

Custom Action with regsvr

I would like to run a custom action on a dll during my installation process.
There is no clean description that I found. So how would you implement this command:
regsvr32.exe /c /n /i:"[PathToIncFolder]" "[BIN]MyFile.dll"
in Wix during the Installation or maybe degister during uninstall?
Preferrably not. The recommended way to install COM components nowadays is to manually add the registry entries.
You definitely should be performing manual registration of the keys and values needed to install the COM component. The reason self-registration is frowned upon is because of problems concerning rollback and uninstall.
The OLE/COM specification should give you information on what keys need to be registered but at a minimum you will need to add a set of entries to a new subkey at HKCR\CLSID\.
Inside this subkey you will need at a minimum, the path to the component and the threading model.
Depending on what your COM component does you may also need to register a PROGID, file-extension maps and APPID.
If the COM object is a managed assembly then your task is slightly different as you need to refer to the .NET bootstrap assembly instead of your own.
If your COM object is written in ATL then your project probably contains a .rgs file which contains all the registry information you'll need.
For further information on COM registry entries check the MSDN here.