How to run .reg files when running the msi? - wix

I am trying to understand how my setup.msi inserts registry values when installing it. In Orca editor I am seeing like this,
After installing the msi, in the log file I am seeing like this,
MSI (s) (A8:B4) [16:27:28:674]: Executing op: ComponentRegister(ComponentId={45667B7F-9DC7-43B7-BE9E-3215ED1B1985},KeyPath=02:\SOFTWARE\myCompany\MySolution\Plugins\MyProduct\ProductCode,State=3,,Disk=1,SharedDllRefCount=0,BinaryType=0)
I want to do the reverse engineering of this mechanism, can any one help me to understand this? I want to recreate the same using WIX, so I just tried like below
<Component Id="RegistryEntries" Guid="*">
<RegistryKey Root="HKLM"
Key="Software\Microsoft\MyCompany"
Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Name="MyApp" Value="[INSTALLLOCATION]" KeyPath="yes"/>
<RegistryValue Type="string" Name="Configuration Files" Value="[INSTALLLOCATIONCONFIG]"/>
<RegistryValue Type="string" Name="Configuration Files1" Value="[INSTALLLOCATIONCONFIG1]"/>
</RegistryKey>
</Component>
When I built the msi and if edit it Orca, I am seeing like below,
What should I do to get the msi as shown in the previous image?

MSI expresses registry data in the Registry table. During the installation, the system determines which features and components are being installed therefore which registry adds, updates and deletes to perform. The actual work is carried out by the WriteRegistryValues and RemoveRegistryValues actions.
It is not a best practice to "execute a reg file" during an installation because it's out of process and MSI can't manage the changes. Instead use the WiX Heat tool to harvest the contents of the registry file into wix xml source for inclusion in your installer.

Related

WIX does not remove shortcuts in the INSTALLDIR if not default

Why WIX does not remove a shortcut in the INSTALLDIR if it is not the default install directory is used? My WIX code look like?
<DirectoryRef Id="INSTALLDIR">
<Component Guid="..." Id="shortcuts_INSTALLDIR">
<RegistryKey ForceDeleteOnUninstall="yes" Id="shortcuts_reg_INSTALLDIR" Key="Software\MyCompany\MyProduct" Root="HKCU">
<RegistryValue KeyPath="yes" Name="shortcut_INSTALLDIR" Type="string" Value=""/>
</RegistryKey>
<Shortcut Arguments="my args " Description="my description" Id="InstallDir_my_name" Name="my name" Target="[INSTALLDIR]mydir\my.exe" WorkingDirectory="INSTALLDIR"/>
</Component>
</DirectoryRef>
It look like that the uninstaller does not know the new value of INSTALLDIR. Any idea?
Windows Installer is a bit of an odd beast here. It doesn't record the operations it performs; instead it tries to record the information necessary to reverse them. In this case it appears you're falling into a gap in that implementation.
Windows Installer notes that it has installed component shortcuts_INSTALLDIR. When a file is installed to a specific directory, it records the directory's location. Then during maintenance it restores all the directories it recorded. But it does not record (and thus does not restore) the directory for just a shortcut. Typically shortcuts are installed to predefined paths under the ProgramMenuFolder. Since such locations are not affected by changes to INSTALLDIR, this is usually not a problem.
To solve this you have to ensure the alternate INSTALLDIR is restored during maintenance. You can convince Windows Installer to do so automatically by installing any file directly to INSTALLDIR (if the extra file is not a problem, this is my preferred option). Alternately you can do so manually through the remember property pattern, possibly leveraging ARPINSTALLLOCATION and its saved value in the Uninstall key.

WiX 3: Error 1406: Could not write value {ValueName} to key {KeyName}

I recently converted an old WiX 2 project to WiX 3. In the previous WiX project there was a component that contained a number of shortcuts, as follows.
<Component Id="ShortcutsComponent" Guid="$(var.ShortcutsComponentGuid)">
<Shortcut Id="Shortcut1" Name="Shortcut1Name" LongName="Shortcut1LongName"
Directory="ShortcutsDir" Target="{Target}" />
<Shortcut Id="Shortcut2" Name="Shortcut2Name" LongName="Shortcut2LongName"
Directory="ShortcutsDir" Target="{Target}" />
</Component>
When I converted the project to WiX 3 this caused the following error.
error LGHT0204 : ICE43: Component ShortcutsComponent has non-advertised shortcuts. It's KeyPath registry key should fall under HKCU.
To resolve the error I made modified the ShortcutsComponent by adding a RegistryValue element as follows.
From our Variables.wxi file.
<?define JAWSVersion = "$(env.Major).0"?>
<?define FSRegistryKey = "SOFTWARE\Freedom Scientific"?>
<?define JAWSRegistryKey = "$(var.FSRegistryKey)\JAWS"?>
And in the WXS file, which includes Variables.wxi, I added the following line to ShortcutsComponent.
<RegistryValue
Root="HKCU" Key="$(var.JAWSRegistryKey)\$(var.JAWSVersion)\Components"
Name="ShortcutsComponent" Action="write" Type="integer" Value="1"
KeyPath="yes" />
I made similar changes to a number of components.
Now I am getting errors when installing the software, but only on some computers. The error is as follows.
Error 1406: Could not write value {ValueName} to key {KeyName}.
System error. Verify that you have sufficient access to that key,
or contact your support personnel.
I considered replacing the above RegistryValue line with something like the following but I do not expect the results to be any different.
<RegistryKey Root="HKCU" Key="$(var.FSRegistryKey)" Action="create">
<RegistryKey Key="JAWS" Action="create">
<RegistryKey Key="$(var.JAWSVersion)" Action="create">
<RegistryKey Key="Components" Action="create">
<RegistryValue
Name="ShortcutsComponent" Action="write"
Type="integer" Value="1" KeyPath="yes" />
</RegistryKey>
</RegistryKey>
</RegistryKey>
</RegistryKey>
Does anyone have any suggestions on how to solve this problem?
NOTE: I was asked to give the precise values for {ValueName} and {KeyName}. Here are the relevant lines from the log file.
MSI (s) (1C:8C) [14:36:29:183]: Executing op: RegOpenKey(Root=-2147483647,Key=SOFTWARE\Freedom Scientific\JAWS\17.0\Components,,BinaryType=1,,)
MSI (s) (1C:8C) [14:36:29:183]: Executing op: RegAddValue(Name=RemoveExploreDir,Value=#1,)
WriteRegistryValues: Key: \SOFTWARE\Freedom Scientific\JAWS\17.0\Components, Name: RemoveExploreDir, Value: #1
MSI (s) (1C:8C) [14:36:29:183]: Note: 1: 1401 2: HKEY_CURRENT_USER\SOFTWARE\Freedom Scientific\JAWS\17.0\Components 3: 1021
Error 1406. Could not write value RemoveExploreDir to key \SOFTWARE\Freedom Scientific\JAWS\17.0\Components. System error . Verify that you have sufficient access to that key, or contact your support personnel.
MSI (s) (1C:8C) [14:40:09:789]: Product: Freedom Scientific JAWS 17.0 -- Error 1406. Could not write value RemoveExploreDir to key \SOFTWARE\Freedom Scientific\JAWS\17.0\Components. System error . Verify that you have sufficient access to that key, or contact your support personnel.
I hope this helps.
This is more of a report of a discovery than an answer. As it turns out the problem was not in the WiX code but in a custom action contained in a DLL that is used by the installer. This custom action created the registry key "HKEY_CURRENT_USER\Software\Freedom Scientific\RJSetup" with the REG_OPTION_VOLATILE option. What this means is that if the "HKEY_CURRENT_USER\Software\Freedom Scientific" did not already exist, it too was created with the REG_OPTION_VOLATILE option. When the WiX installer attempted to write to any key under "HKEY_CURRENT_USER\Software\Freedom Scientific" this caused the Error 1406. We are fixing the custom action so that it first creates the "HKEY_CURRENT_USER\Software\Freedom Scientific" registry key as a standard key and then creates the "HKEY_CURRENT_USER\Software\Freedom Scientific\RJSetup" registry key with the REG_OPTION_VOLATILE option. That hopefully will fix the problem.
The moral of the story is, if you find an odd error in a WiX installer that you cannot figure out in code that appears to be consistent with thousands of resources found online consider the possibility that you are shooting yourself in the foot in one of your custom actions.

Wix - How to get user input from a previously installed msi?

I'm trying to do an installer using wix 3.8. I can use custom properties to store my own input, but I'd like to use values that where inputs on a previously installed msi.
Is there a way to accomplish such thing?.
To get you in the right direction add this (of course adapt it to your needs first) in your fist MSI:
<DirectoryRef Id="INSTALLDIR">
<Component Id="RegistryEntries" Guid="{0AC76129-F8E2-47D3-B9FD-09B1E10A8541}">
<RegistryKey Root="HKLM" Key="Software\Company123\App123" Action="create">
<RegistryValue Type="integer" Name="SomeIntegerValue" Value="1" KeyPath="yes"/>
<RegistryValue Type="string" Name="UserInput" Value="[USERINPUT]" />
</RegistryKey>
</Component>
</DirectoryRef>
Don't forget reference the component in your <Feature> <ComponentRef Id="RegistryEntries" />
When you install assign a value to the property [USERINPUT] e.g. msiexec /i your.msi /qb+ USERINPUT="the value to be saved in registry"
Then in the second MSI add something like this:
<Property Id="READREGISTRY">
<RegistrySearch Id="USERINPUT_Value" Root="HKLM" Key="Software\Company123\App123" Name="UserInput" Type="raw" />
</Property>
The value/string you entered during installation USERINPUT= will be stored in your second MSI in the property READREGISTRY
Here a piece of log in my second msi:
PROPERTY CHANGE: Adding READREGISTRY property. Its value is 'testing registry wef wef wef w'.
Based on your installation where it might be Per User or Per Machine you may adjust the Root to HKCU for PerUser installs or leave it to HKLM for PerMachine.
For more information please refer to Wix documentation, hints: "How To: Write a Registry Entry During Installation" and "How To: Read a Registry Entry During Installation".
Generally, no. There is no requirement for a Windows Installer package to record the input it takes from the user. Some do record some information in the registry and you might choose to rely on finding it there.
As an alternative, you might find that the other installer can be run without a UI and can be sufficiently controlled with properties passed into it. If so, you can write your own UI (one way would be a custom WiX Bootrapper Application [example]) to gather the inputs before running the installer.
Create a custom action within the MSI which gets installed first, then either write the values/user entries that you want into a file or registry. Within your final MSI read the values from registry/file and use it.
Here is an example of how you can read a value from the user and update the your app.config, this is not an apple to apple scenario, but this will guide you through it.
http://bensnose.blogspot.com/2013/03/more-custom-actions-with-wix.html
Disclaimer: I havent tried out what is mentioned in this blog post, but I have done things very similar and found that it has good explanation, thats why I posted the link to it.

Wix registry editing not displayed in the msi log

I've been working on a WIX .net project that needs to update a Microsoft registry entry to work correctly. While testing the logic, I found it difficult to debug the WIX components that updates the registry via the MSiexec.exe command line /log options. To verify the correct behaviour, I had to check the registry value manually. How do I force the WIX project to log the registry search and update logic from the following fragment in the MSI log output?
<util:RegistrySearch Id="Office2013RegistySearch"
Root="HKLM"
Key="SOFTWARE\Microsoft\Office\15.0\Access Connectivity Engine\Engines\Excel"
Value="TypeGuessRows"
Variable="Office2013GuessRowsx86Exist"
Win64="no"
Result="exists" />
<Component Id="Office2013GuessRowsx86RegComponent" Guid="CFE579F9-292A-4777-A671-B5E8E330B1A0" Win64="no">
<Condition>Office2013GuessRowsx86Exists</Condition>
<RegistryKey Root="HKLM"
Key="SOFTWARE\Microsoft\Office\15.0\Access Connectivity Engine\Engines\Excel" ForceDeleteOnUninstall="no">
<RegistryValue Type="integer" Name="TypeGuessRows" Value="0"/>
</RegistryKey>
</Component>
Try use full log
msiexec /i "dotnetproject.msi" /L*v "log.log"
or add <Property Id="MsiLogging" Value="voicewarmup"/> (for full log too)

Remove registry keys under HKCU on a per machine installation

I build a perMachine installer using WiX 3.6 to install a software I had not developed. Unfortunately the software creates some registry keys under HKCU during execution.
On uninstall, the self created keys should also be removed. It seems not so easy to remove these keys. I am "fighting" with ICE57 and/or ICE38. Both complaining the mix between perUser and perMachine data.
Hopefully you can point me in the right direction on fixing this issue.
To overcome ICEs you should move Per-User registry to separate components and use some registry entry as keyPath for that component, i.e.:
<Component Id='PerUserRegistry' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" KeyPath="yes" Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\[ProductCode]\PerUserRegistry" Name="[PackageCode]" Value="[ProductVersion]" Type="string" />
<!--Other Per-user registry goes here-->
</Component>
I completely agree with Christopher: It is common practice to leave per-user data on uninstall, but if removal is necessary, then Active Setup is the only real option.
First I propose you to remove them on Install or Re-Install instead of uninstall, you just need add RemoveRegirty entry and Active Setup, i.e. with this WiX code:
<Component Id='ActiveSetup' Guid='*'>
<RegistryValue Id="ActiveSetup00" Root="HKLM" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RegistryValue Id="ActiveSetup01" Root="HKLM" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Value="[ProductName] [ProductVerion] Configuration" Type="string" />
</Component>
<Component Id='PerUserRegistryCleanup' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPath" Root="HKCU" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RemoveRegistryKey Id='PerUserRegCleanup' Root='HKCU' Action='removeOnInstall' Key='Key\To\Be\Removed'/>
</Component>
Note: [PackageCode] use in ActiveSetup is very recommended, so with each new version (build) of MSI package you add separate entry (also see my final note). I used per-user active setup registry as key-path on purpose, so you don't run it for current user twice.
As for removing them after uninstall,
Now, hopefully you need to remove entire key, and not just some values. In either case, I would create custom action to add Registry entry for Active Setup during uninstall (or if there are many such keys/values, create and deploy .CMD file with those and launch it on uninstall, before RemoveFiles action, to add all of them to registry).
Note: that I would strongly recommend adding deleting this registry during install, or you might end up removing per-user values when software is yet installed.
So here's WiX code for all of this:
<CustomAction Id="CA_UninstallRegistryCleanUp" Directory="SystemFolder" ExeCommand="REG.exe ADD "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp" /v StubPath /d "reg add ^"HKCU\Key\To\Be\Removed^" /va /f" /f" Return="ignore" />
<InstallExecuteSequence>
<Custom Action='CA_UninstallRegistryCleanUp' After='RemoveRegistryValues'>REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
<Component Id='RegCleanup_Remover' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" Root="HKLM" KeyPath="yes" Key="SOFTWARE\[Manufacturer]\[ProductName]\[ProductCode]\" Name="DummyKey" Value="[ProductVersion]" Type="string" />
<RemoveRegistryKey Id='RegCleanup_Remover' Root='HKLM' Action='removeOnInstall' Key='SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp'/>
</Component>
Final notes:
There just two small issues with all this Active Setup stuff: be careful on Windows Terminal Servers; and once active setup was run for one user for current .MSI, it will not run again if you decide to reinstall same package, unless you change its PackageConde or raise version under ActiveSetup registry key. These are topics for another day, let me know if need them clarified.
And don't forget to add all of above Components to some Feature.
The Windows Installer considers this user data and best practice is to not remove it. Either way, it's very difficult to try to remove it anyways since other user profiles are out of scope / context. It's theoretically possible to write a custom action to enumerate profiles and load registry hives but on some versions of Windows ( Vista ) that won't work due to restricted permissions granted to the windows installer service.
If you really, really must be able to remove custom action data on uninstall then take a look at:
Active Setup Explained
You are going to need to leave behind an program (exe for example ) by marking a component as permanent. Then you'll need a custom action to write a registry value during the uninstall (because Windows Installer doesn't support this).
The concept is during the install you lay down an EXE and during the uninstall you leave you. You then write to the ActiveSetup registry key telling it to run your EXE once for each subsequent user to logon to the machine. The EXE then deletes your registry values. Reboot (politely) if needed to unload the extensions from explorer.
But honestly, a better designed application wouldn't need all of this.