I have an application that is saving multiple registry keys on install to ensure that certain choices a user makes are persisted in the application. Most of these keys work correctly, but some do not record an entry. Am I doing something wrong? or is there a limit on the WiX RegistrySearch? I have checked the documentation and can't find any limit. I have included some examples below :
The following works correctly:
<Property Id="SERVER_NAME">
<RegistrySearch Id='rsSERVER_NAME' Root='HKLM' Key='SOFTWARE\CompanyName\ApplicationName' Name='ServerName' Type='raw' />
</Property>
The following does not work correctly:
<Property Id="SERVER_NAME">
<RegistrySearch Id='rsSERVER_NAME' Root='HKLM' Key='SOFTWARE\CompanyName\ApplicationName\ApplicationDetails\Servers' Name='ServerName' Type='raw' />
</Property>
Is there any reason why the 2nd code block would not work?
If you want to persist property values from user choices it may be easier to just let WiX do it with the "remember property" pattern.
It's not clear how you are saving these values and retrieving them, because there is no indication if you are saving them in 32-bit or 64-bit location, or if you are using the -arch switch to set the default, so it may be that you are saving or restoring them from different bitness locations (see RegistrySearch win64 setting). Without this context it's not clear if that search will work or not. It appears to be a 32-bit search in the absence of Win64=yes, but the -arch switch changes the default.
TEST OK: I ran a test of this and both values were retrieved from the 32-bit section of the registry (HKLM\SOFTWARE\WOW6432Node) without any problems.
Here is the WiX RegistrySearch documentation. And below are the registry paths mentioned by Phil for 64-bit and 32-bit applications - your WiX code specifies 32-bit, so you read from the WOW6432Node section:
HKLM\SOFTWARE (for 64-bit applications)
HKLM\SOFTWARE\WOW6432Node (for 32-bit applications - believe it or not)
I am wondering if you are just mixing up the paths in the registry? Here is where I am reading from - it is in HKLM of course (I cropped the screenshot a bit to make it fit the page):
UPDATE: I have now tested this reading from both the 32-bit and 64-bit sections of the registry. It works as expected as far as I can see? There must be an error in your registry path somewhere?
I use a one-line VBScript to show the property value after the RegistrySearch has run and retrieved the properties. I can update this answer to add this code if you want.
It is a little unclear what you mean when you say that an application is saving multiple registry settings during installation. Is this a custom action you are running which writes these registry keys, and then your setup reads them back?
It is unclear how these values - that you read back from the registry using RegistrySearch - are actually written to the registry? Perhaps they are from a prior version of your application or from another application and you want to "copy" them? If so, can you verify whether they are HKCU or HKLM settings? For HKCU settings I would prefer to do the copy in the application itself for reliability reasons.
Related
I have a merge module which searches for some registry locations to read values and save to Properties. Here is the code segment:
<Fragment Id="RegSearch">
<Property Id="HOST_APP_PATH" >
<RegistrySearch Id="HOST_App"
Root="HKLM"
Key="SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\HOST.exe"
Name="Path"
Type="raw"
/>
</Property>
<Property Id="HOST_ROOT_PATH" >
<RegistrySearch Id="HOST_Root"
Root="HKLM"
Key="SOFTWARE\HostApplication\Installation Info"
Name="HOST_Root"
Type="raw"
/>
</Property>
Windows Installer puts this search in AppSearch custom action.
Problem: AppSearch executes this search very early, before WriteRegistryValues of Host Installer, it won't get any values and properties with this search won't be defined, because registry to search was never written there.
Question 1: Can we reschedule this registry search from merge module after WriteRegistryValues of Host Installer?
Question 2: Is there any other way to search registry after Host Installer executes WriteRegistryValues? Probably with some custom action?
AppSearch is a standard action provided by the windows installer and by design is intended to run very early. This is because it's frequently used by the LaunchConditions standard action to decide if an installation can continue or not. It's also useful for deciding whether features and components should be installed.
MSI is a very opinionated framework. I suspect that there is something wrong with your current design that is going to be incompatible with MSI.
Is host installer the same MSI or a different MSI? Assuming it's the same, why couldn't you just put your data in some MSI properties and use those properties to write to the registry? Then you wouldn't need to read the values back in because you'd already have them in properties.
What do you need these properties for after writing them to the registry? Usually writing them to the registry would be the end game. I'm not sure what else you are doing next.
If host.msi is a different MSI, why are you having one MSI install another MSI? That's not MSI design. In this case you would need a bootstrapper. Host MSI would run first then this MSI. But even then it's kinda strange that a second MSI would depend on properties set by a first MSI. I'd think the bootstrapper UI and Application would gather this information and pass it as secure custom public properties to both MSIs.
To answer question 1: No a merge module can only insert actions into the sequence. It can't reschedule actions. 2: You would have to use a custom action. But as I said above, this feels like the wrong path to me.
I am using wix registry search in order to locate a plugin directory for a program I am trying to integrate with. The value of the registry key looks like this:
%PROGRAMFILES%\Product\Plugins
When I do a registry search with type="raw" like this:
<Property Id="PLUGINDIR_STRING">
<RegistrySearch Id="PluginDirSearchString"
Root="HKLM"
Key="$(var.PluginDirRegKey)"
Name="$(var.PluginDirRegKeyName)"
Type="raw"
Win64="yes" />
</Property>
I will get the exact string.
When I use type Directory like this:
<Property Id="PLUGINDIR">
<RegistrySearch Id="PluginDirSearch"
Root="HKLM"
Key="$(var.PluginDirRegKey)"
Name="$(var.PluginDirRegKeyName)"
Type="directory"
Win64="yes" />
</Property>
I will get an empty string. I am checking the values like this:
<Condition Message='plugin dir "[PLUGINDIR_STRING]" found using registry key "$(var.PluginDirRegKey)" is not a valid path, make sure the path exist'>PLUGINDIR_STRING AND NOT PLUGINDIR</Condition>
<Condition Message='Unable to find registry key "$(var.PluginDirRegKey)", make sure $(var.PRODUCT) is installed'>PLUGINDIR_STRING</Condition>
The first message is displayed indicating that PLUGINDIR_STRING is found, but not PLUGINDIR. I thought the Directory option should expand %programfiles%? How to correctly handle a registry value like this?
%PROGRAMFILES%\Product\Plugins
The raw search does not work the same as directory search. A raw search returns the values in the registry item. A directory search retrieves the value then checks to see if that registry exists - it literally is a directory search for the directory in that registry item and if it doesn't exist then it will not set the property value. The idea is that if you want to use that directory as an install location it tells you that it doesn't exist.
Anyway a verbose log should verify if this is going on - look at the AppSearch and you may find something like a 1314 error saying that the directory in that registry item does not exist.
I cannot reproduce the error you are seeing. Both raw and directory registry searches are expanding %programfiles% correctly. Everything else you are doing seems correct, so the most likely issue with your failing directory search is that your setup is a 32-bit setup and you are attempting to locate a 64-bit directory. Your AppSearch in a 32-bit install will locate the %programfiles% string in your registry entry, but it will invoke WIN64DUALFOLDERS, and search for the directory in the ProgramFiles(x86) folder. If the directory isn't there you will see an empty property value returned.
Use the well defined MSI property to get the program files location.
You can find the list of well defined properties here
So set your property to [ProgramFilesFolder]\Product\Plugins. There is also ProgramFiles64Folder but from the snippets you supplied I can't tell which one you should be using. Ideally you use a 32-bit installer to install into Program Files on a 32-bit OS and Program Files (x86) on a 64-bit OS and you would use a 64-bit installer to install into Program File on a 64-bit OS.
I try to create a MSI Single Package using WIX (3.10). The user can select in the UI whether the package should install Per-User or Per-Machine. The package is initialized with ALLUSERS=2 and MSIINSTALLPERUSER=1. I did not set an InstallScope, as this would limit the Package to one or the other.
If the user selects Per-Machine the setup continues with ALLUSERS=2 and MSIINSTALLPERUSER="". - Everything works as expected.
If the user chooses Per-User installation ALLUSERS=2 and MSIINSTALLPERUSER=1 remain unchanged. If a non-privileged user runs the setup everything works as expected as well.
But if a privileged user executes the setup and chooses Per-User installation, registry keys that should be written to HKCU\Software\Classes\ are still written to HKCR / HKLM\Software\Classes\. This happens without UAC being invoked.
I observed this behavior on a Windows 8.1 (current patch level).
This is not what I want. If the user selects Per-User installation, there should be nothing written to HKLM/HKCR.
Here is sample from the wxs-file:
<Component Id="MyRegistryComponent" Guid="{99999999-9999-9999-9999-999999999999}">
<RegistryValue Id="MyRegistryComponent_MainKey" Root="HKCU" Key="Software\Classes\myapp.myclass" Value="myapp.myclass.foo" Type="string" />
</Component>
I checked the MSI with Orca. This RegistryValue has Root=1 in the Registry table of the MSI.
I tried/checked already:
I verified that the ALLUSERS and MSIINSTALLPERUSER properties are
indeed set as stated above.
I tried setting ALLUSERS="" MSIINSTALLPERUSER=1 – No effect.
I changed Root="HKCU" to Root="HKMU" in the wxs.
This results in Root=-1 in the MSI, but I does not change the final
result after installation.
What am I missing here?
Is possible that this behavior is caused by previous incomplete (un-)installations?
When you say "This results in Root=-1 in the MSI, but I does not change the final result after installation." it's not clear which of the results you're referring to but:
HKCU will always go to HKCU, HKMU is what you need to switch between HKCU and HKLM in a single package setup. So using HKMU and producing a verbose log would be useful to see if there is a failure somewhere in there.
You will get changes in HKCR. That's usually the normal behavior because as this article explains:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
Quote "The HKEY_LOCAL_MACHINE\Software\Classes key contains default settings that can apply to all users on the local computer. The HKEY_CURRENT_USER\Software\Classes key contains settings that apply only to the interactive user. The HKEY_CLASSES_ROOT key provides a view of the registry that merges the information from these two sources. HKEY_CLASSES_ROOT also provides this merged view for applications designed for previous versions of Windows."
HKCR is a virtual view that combines class registration for the current user with class registration for the machine to present a view of all class entries on the system. Other accounts (such as the system account) will see only HKLM, so what you see exactly depends on who you are.
I suggest that is what is needed here is a test case that uses HKMU as is required, and maybe post that test case. Keep in mind that seeing HKCR entries is normal, going by the documentation, so maybe that explains all that you are seeing.
I am trying to configure Wix to build my msi to only perform build versions (1.0.x) of my product in conjunction with the REINSTALL property, my problem is that when I run the command line: MSIEXEC.exe /i my.msi /l*vx build-inst.log REINSTALL=ALL REINSTALLMODE=vamus it fails to do anything.
I have checked the msi log and found that it is looking for the existing product in the default folder (.\program files (x86)...\myproduct) yet when I installed it the first time I actually used a custom path (c:\myproduct). It was my impression that using REINSTALL the installer would use the installed path of the original product.
Is this actually the case? Should I be specifying the INSTALLDIR on my command line? I would rather not as this is meant for use by clients and I cannot guarantee I will know where the product was installed.
This method of performing "build" upgrades has been suggested in a couple of places but I can not find anything explaining any need to specify the INSTALLDIR
Is there any way to configure this in Wix?
Thanks
Kieran
The easiest solution would be to store the installation directory in the registry and look it up upon reinstalling.
To look up your registry value, you'd use something of the sort:
<Property Id="INSTALLDIR">
<RegistrySearch Id="InstallLocation" Root="HKCU"
Key="SOFTWARE\Company\Product" Name="Location" Type="raw" />
</Property>
If the registry value isn't found, the INSTALLDIR property will be set to your directory structure.
Rob has a complete solution on his blog for when you specify such a property from the command line.
Normally the original entries in the directory table are stored for reinstall without that you store them yourself.
So there is something "special" in your MSI, if this doesn't work. If you have a custom action which sets directory properties like INSTALLDIR, you should not use it. E.g. give them a condition "Not Installed".
I found out that the problem was due to using a wildcard for the product id, so every time a new msi was built it created a new product id.
By fixing this it seemed to resolve the problem, though I have also implemented the registry key option as it will help for upgrades where I do want to change the product id.
Thanks
I'm making an installer with the WiX 3.5 toolset, and I've run across a problem:
The installer needs to be able to detect whether another program is present, and if so, add a DLL file in its directory. I use the following code to figure out where the second program is installed:
<Property Id="FIND_INSTALLDIR" Value="[%ProgramFilesFolder]\PROGRAM">
<RegistrySearch
Id="INSTALLDIRSearch"
Root="HKLM"
Name="UninstallString"
Type="file"
Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PROGRAM"
/>
</Property>
The trouble is, if the second program isn't installed, Windows Installer gives me an error:
Could not access network location [%ProgramFilesFolder]\PROGRAM
I need to be able to handle this gracefully, though... how do I recover from the error?
Perhaps this will help you:
Detecting the presence of a directory at install time
Basically, you need to make sure that the property you are using for the DLL folder is set to a valid path, even if the DLL will not be installed (the actual path was not found).
With Cosmin's help, I found the solution:
All I had to do is to not set Value, so that it wouldn't try to find the folder... everything else worked perfectly!