Register ActiveX exe server using WiX - com

I have several VB6 ActiveX server exe files which need to be registered on install before they can be used.
I have tried using Heat to extract the information but it only generates a file element.
These files can be registered by calling them with the /regserver switch and unregister by calling them with the /unregserver switch. I understand this is not the correct way to this. Instead I should add the registry keys and other required elements to my wix source.
My question is how do I find out what registry keys and other element I require to register these ActiveX exe files. Seeing as Heat seems unable to harvest this information.

how do I find out what registry keys
and other element I require to
register these ActiveX exe files
In general, you can discover registry changes like this:
Bring the registry in a clean state,
e.g. use myapp.exe /unregserver
Create a dump of the registry
content like this
c:\WINDOWS\system32\reg.exe export dump1.reg
Run the command that will change the registry, e.g. myapp.exe /regserver
Create another dump2.reg of the
registry.
Find the differences between
dump1.reg and dump2.reg with a
diffing tool (e.g. TortoiseSVN
adds a "diff" command to the
explorer context menu when you have
two files selected)
There might be some noise in the differences that you should ignore. A typical example is HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\RNG\Seed. This registry key is used by the windows CryptoAPI to store continuously gathered entropy. Incidentally, this key sometimes shows up in MSI packages generated by commercial setup generators. This seems to indicate that they use a similar registry-sniffing technique :-)

I had the same problem with tallow from WiX 2.0 and had to implement registry harvesting for out-of-proc servers. Here is the patched tallow. Would be nice to merge the ProcessWithInjectedDll class to Heat and probably converge to the main trunk at some point.
Beware that lots of cruft from VB6 runtime gets in the generated registry keys. The generated output is unusable without some tweaking. That's when CleanupRegInclude.vbs can be useful.
Last but not least, absolute filenames and paths are useless. You have to use #YourComponent and $YourComponent instead (check the MSI documentation).

ActiveX controls are just COM objects. The minimum amount of registration you need to do is something like this:
<RegistryKey Root="HKCR" Action="createAndRemoveOnUninstall" Key="CLSID\{YOUR-GUID-HERE}">
<RegistryKey Action="createAndRemoveOnUninstall" Key="InprocServer32">
<RegistryValue Action="write" Value="[INSTALLDIR]YOUR-DLL-HERE.dll" Type="string"/>
<RegistryValue Action="write" Name="ThreadingModel" Value="Apartment" Type="string"/>
</RegistryKey>
</RegistryKey>
You may want to register a Prog ID:
<RegistryKey Action="createAndRemoveOnUninstall" Key="ProgID">
<RegistryValue Action="write" Value="YOUR.PROGIDHERE" Type="string"/>
</RegistryKey>

I thought heat.exe had been updated to be able to harvest COM EXE files, but I guess it might not have been implemented yet.
I normally use a tool called RegSpy / RegSpy 2 to extract COM info from DCOM EXE files: http://www.installsite.org/pages/en/tt_analyze.htm#RegSpy.
Using the above tool will give you a reg file, but you will still need to convert to WIX format. To get the reg file you go:
regspy2.exe myfile.exe >> myfile.reg
I don't think there is a way to automatically convert a reg file to wxs format (I remember writing a basic converter a while ago, but don't have it here). To make this easy you can extract the info required using Installshield or Wise For Windows Installer, build an MSI and then disassemble the msi to Wix format using the dark.exe (wix decompiler). The resulting Wix markup can then be added to your project.

I tried both heat and the regspy mentioned by #Glytzhkof but found that neither did a complete extract of all the relevant registry info for my COM server. I did however find a utility - RegSpyUI - that sort of ships with InstallShield which did a lovely job. Described in more detail here.

Related

Registering COM EXE with WIX

I created a solution with two new projects: ATLProject1 which is a COM dll and ATLProject2 which is a COM EXE. To both projects added same simple class with single method.
Added both to WIX setup project (this is an existing setup project that already installs other COM dlls. I'm just using it for this test).
Added following lines to product.wxs:
<Component Id="ATLProject1.dll" Guid="{...}">
<File Id="ATLProject1.dll" Name="ATLProject1.dll" KeyPath="yes" SelfRegCost="0" Source="$(var.TargetDir)\ATLProject1.dll" />
</Component>
<Component Id="ATLProject2.exe" Guid="{...}">
<File Id="ATLProject2.exe" Name="ATLProject2.exe" KeyPath="yes" SelfRegCost="0" Source="$(var.TargetDir)\ATLProject2.exe" />
</Component>
and also
<ComponentRef Id="ATLProject1.dll" />
<ComponentRef Id="ATLProject2.exe" />
The file also has these lines:
<EnsureTable Id="PublishComponent"/>
<EnsureTable Id="Condition"/>
<EnsureTable Id="TypeLib"/>
<EnsureTable Id="Class"/>
<EnsureTable Id="Extension"/>
When running the setup I get error: "Module ATLProject2.exe failed to register. HRESULT -2147024769" (hex 0x8007007f the specified procedure cannot be found).
If I remove ATLProject2 from setup, it succeeds and ATLProject1 is correctly registered in registry (this is without generating registry information e.g. using heat, it just works).
Should exe component be treated differently?
I found this 10 year old post suggesting heat.exe does not treat COM exe as COM. If this is the problem, Not sure if this is still the case?
The Windows Installer does not recommend using SelfReg to register at install time. Instead, adding the registration to your .wxs code or capturing the registration at build time is highly recommended.
To add the registration manually, you don't use EnsureTable, you use the COM related elements (like Class, ProgId, TypeLib). It can be tedious but will be far more robust than trying to selfreg during installation.
Unfortunately, the alternative to capture the registration during build using heat.exe (provided in the WiX toolset) does not support capturing from executables. If you are open to a commercial solution, we (FireGiant) developed an alternative to heat.exe that can capture executable registration (and much more). That advanced harvesting solution has more documentation on the FireGiant site.
RegServer Switch: COM EXE files are normally self-registered via the /RegServer switch as in:
MyBinary.exe /RegServer
In other words EXE files are not registered via the normal regsvr32.exe mechanism. This is the tool used to register COM dll's and OCX files, but it does not handle EXE files. There is also an /UnRegServer switch to unregister EXE COM files - for the executables that support /RegServer (which is not all COM EXE files - it could be missing as a feature).
Self-Registration: Self-Registration is not ideal to register COM files, and here is a write-up of why this is the case: MSI register dll - Self-Registration considered harmful. In MSI one extracts the COM registry data and populates a number of special COM-tables to allow the registration of the COM server in a way that supports advanced features such as rollback. I don't like the COM extract either (risk of self-repair problems, more on self-repair problems), but it helps in most cases - especially when there are dependencies that can trigger registration problems. Moreover it is the way COM files are supposed to be registered in MSI. It is the standard. I should note that some COM settings go into the Registry table still - since there are no dedicated COM-related tables for them.
heat.exe: WiX's own heat.exe tool now can extract COM data from dll files and ocx files (32-bit). But it does not seem to work for EXE COM files - I am not sure why:
heat.exe file MyCOMDll.dll -out MyCOMDll.wxs
RegSpy2.exe: There is a tool you can use to extract COM registration information from both DLL, OCX and EXE files. It can be downloaded from here: http://www.installsite.org/files/iswi/RegSpy2.zip. Here is the main page listing numerous tools. The RegSpy tool is written by Phil Wilson - MSI Expert and author of The Definitive Guide to Windows Installer (APress).
Here is how to extract the COM data from a COM executable (if you get no data, try unregistering the file first and then running regspy.exe):
RegSpy.exe MyBinary.exe /RegServer >> RegistryOutput.reg
The exported *.reg file can then be converted to WiX elements. This is not an easy process. Using the WiX tool heat.exe does not populate the proper COM tables, but rather puts everything in the Registry table (which will work though, barring MSI validation errors):
heat.exe reg MyCOMRegistryData.reg -out MyWiXFile.wxs -sfrag -suid
There used to be a tool called Tallow that converted reg files to WiX COM registration, but this tool is no longer anywhere to be found. I am not aware of any other ways to generate it short of writing it yourself, or download another deployment tool and import the COM data or extract it and decompile the generated MSI with dark.exe and take out the WiX markup. Or figure out how heat.exe writes its WiX XML output with COM data and adapt that to process the output from RegSpy.exe.
UPDATE: Throwing in a link to Paraffin: https://github.com/Wintellect/Paraffin. This is supposedly a "better Tallow". I am not sure what it supports in terms of COM-extract. My quick test seemed to indicate it doesn't support COM extraction at all, but supports auto-generating WiX markup and add and remove files for updates.
Custom Actions: It is possible to register your COM EXE by means of a custom action that calls the /RegServer switch as well, though this is not recommended for all the reasons listed in the link above (self-registration considered harmful).
Some Links:
Adding a .reg file to registry WIX
How to generate WiX XML from a .reg file?

How to include inherited permissions when specifying permissions for a file installed by Wix / Windows Installer?

The Wix source code that I feed to the Wix compiler to build an MSI package for my application, contains the following PermissionEx directive, part of a file component which Windows Installer should install with additional (to those that should be inherited by default) permissions:
<PermissionEx Sddl="D:AR(A;;FW;;;BU)" />
As you can surmise, I intend to install the file with inherited permissions ("AR") included in its ACL and on top of that allow members of the Built-in Users group ("BU") to be allowed ("A") to write to the file ("FW").
The code above does not have the desired effect -- the file is installed, but only that single explicit ACE is listed, none of the ACEs that are supposed to be inherited from parent folder.
In contrast, if I subsequently remove all permissions from the file and run cacls file /S:D:AR(A;;FW;;;BU), i.e. specify exactly the same SDDL string, it does work as intended -- the permissions from parent are inherited and form part of the ACL, together with the explicit non-inherited ACE.
I am using Wix 3.11.1.2318 and the Windows Installer version is 5.0.16299.611, all running on Windows 10 Enterprise 64-bit. Orca tells me the MsiLockPermissionsEx table embedded in my built MSI file is populated with the intended SDDL record. So why is the file created without inheriting permissions from its containing folder?
I tried to use "AI" in place of "AR", and both strings together, but none of it had any effect either.
Is this some known limitation or a quirk with Windows Installer? I know that people were talking a while back how the old LockPermissions table (the one specified for Windows Installer versions earlier than 5) was inadequate in this specific regard -- inherited permissions, namely -- but they also said Microsoft was out to address this very issue with the new table feature.
Otherwise what am I doing wrong?
Given your knowledge in this field, you probably have already tried this. It would also be much better to eliminate the need for permissioning, but two snippets for you - notice the Append attribute:
Create a WiX project in Visual Studio. Add the Util namespace to the WiX element:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
In Visual Studio project, right click References and add reference to "%ProgramFiles(x86)%\WiX Toolset v3.11\bin\WixUtilExtension.dll".
Permission Folder:
<Component Feature="ProductFeature" Id="Test.exe" Guid="PUT-GUID-HERE">
<File Source="C:\Test.exe" />
<CreateFolder>
<util:PermissionEx User="Power Users" GenericWrite="yes" />
</CreateFolder>
</Component>
Permission File:
<Component>
<File Source="C:\Test2.exe">
<util:PermissionEx Append="yes" User="Users" GenericWrite="yes" />
</File>
</Component>
Take a look at WiX's custom PermissionEx in the Util extension.
http://wixtoolset.org/documentation/manual/v3/xsd/util/permissionex.html

Should the installed entry in the registry be in the Microsoft folder?

When adding a shortcut to an installer created with Wix, according to How To: Create a Shortcut on the Start Menu, you need to add a registry value with like this:
<RegistryValue Root="HKCU" Key="Software\Microsoft\MyApplicationName" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
Should that value really be inside of Software\Microsoft? In many cases in the Microsoft world I'm seeing the vendor used as the scope so I'm wondering if it shouldn't really be Software\MyVendorName\MyApplicationName.
I would definitely write to my own location as indicated by others:
HKCU\Software\MyVendorName\MyApplicationName
HKLM\Software\MyVendorName\MyApplicationName
Ideally your application should not write anywhere else in the registry - except beneath these two parent locations. You "own" these two registry locations - and nowhere else. You shouldn't write anywhere else - and certainly not under the Microsoft key. I believe that is a "generic sample".
The exception is when you need to register certain files (or components) - for example COM files whose registration go into HKLM\SOFTWARE\Classes and HKCU\SOFTWARE\Classes. These per machine and per-user locations are merged to produce HKCR (HKEY_CLASSES_ROOT). COM registration can also be isolated, in which case you use manifest files - then the registry is not involved at all. WiX features special COM-related elements that will populate the registry for you via standard MSI mechanisms - the heat.exe tool for harvesting COM registration (among other things) will auto-generate these elements for you and your compiled MSI will have several MSI tables keeping the COM registration information (ProgId, Class, TypeLib, etc...).
UPDATE: Not to compliate things too much, but an MSI can be installed per-user or per-machine based on the values of ALLUSERS and MSIINSTALLPERUSER properties. If you have populated the proper COM tables in the MSI the COM server will be registered per-machine or per-user accordingly.
And there are other cases where installation processes make changes elsewhere in the registry if you install your package. For example when you install drivers, plug-ins, fonts, COM+, COM Interop, file extensions, etc... Your registration in these cases should generally go through APIs that take care of registering your components and you should not poke around i the registry yourself in most cases. A lot of such registration is handled by MSI if you do it right - or built-in constructs in third party tools used to make MSI files.

vsdrfCOMSelfReg equivalent for WixSharp

I am trying to recreate the functionality of a legacy installer using WixSharp. In the legacy Setup Project, some of the third party DLL's were marked "vsdrfCOMSelfReg". I have seen in various places that you can add to the File tag SelfRegCost="0" but it is highly frowned upon.
How can I properly register a COM DLL using WixSharp? Is there a way to just add SelfRegCost field to the File tag for the DLL from WixSharp?
It's true that you can say something like SelfRegCost=1 in the File element, but every install guy will tell you it's evil, as you discovered. The non-evil way is to use heat.exe on the Dll to extract the registration data into a wxs file. If necessary add interface entries for type library data by running heat.exe on a tlb file. Heat is just a WiX tool, I don't see how WiXSharp is involved.
The point is that registration data is static and can be stored in the MSI via WiX and simply written to the system at install time without requiring the Dll to be loaded and called.
After some further source browsing and experimentation, I figured out how to force the evil approach through WixSharp. I also later discovered that this was somewhat covered by the WixSharp Sample "CustomAttributes".
"Evil Way"
File LibToReg = new File("..\Path\To\LibToReg.dll");
LibToReg.AttributesDefinition += "SelfRegCost=1";
Alternatively (based on the CustomAttributes sample):
File LibToReg = new File("..\Path\To\LibToReg.dll")
{
Attributes = new Attributes() { { "SelfRegCost", "1" } }
};
This will generate the following wxs underneath:
<Component Id="Component.LibToReg.dll" Guid="EABD7A49-26DD-4720-AE5A-AA9EEFD8C91A">
<File Id="File.LibToReg.dll" Source="..\Path\To\LibToReg.dll" SelfRegCost="1" />
</Component>
The rest of the generated code looks the same as any other DLL that is installed.
For reference, here is the original wxs source that was generated from the original Setup Project using "VDProj to WiX Converter" from Add-In Express. I believe the SelfRegCost="0" was added by the converter, but a co-worker may have manually added it in afterwards.
<Component Id='com_FB7105EC_5352_4561_AE01_405562F0EA1E' Guid='6718170E-0335-4FD6-A1E8-D9E926DDE3EC' Permanent='no' SharedDllRefCount='no' Transitive='no'>
<File Id='_FB7105EC_5352_4561_AE01_405562F0EA1E' DiskId='1' Hidden='no' ReadOnly='no' SelfRegCost='0' System='no' Vital='yes' Compressed='yes' Name='LibToReg.dll' Source='..\Path\To\LibToReg.dll' KeyPath='yes' />
</Component>

How do I get a shortname for a folder in WiX for a Windows Installer property?

I am trying to register an out-of-process COM file (.exe) through WiX after extracting the COM registration from regspy.exe, and am running into the problem that the registry key I need to write is:
<RegistryValue Value="C:\PROGRA~1\COMMON~1\file.exe /Automation" Type="String" />
Now I would like to use the Windows Installer property [CommonFilesFolder] as not everyone installs to C:\
For an in-process (.dll) the long name is acceptable:
<RegistryValue Value="[CommonFilesFolder]file.dll" Type="string" />
But it appears this in not true for out-of-process. Is there a way to convince or convert [CommonFilesFolder] to the short name? This is a particular problem for x64, as the name will resolve to C:\PROGRA~2\ instead of C:\PROGRA~1\
Use [!idOfFile] to get the full short path. (See Formatted in MSI SDK for the full list of special formatting keys.)