%programfiles% is not expanding in wix registry search - wix

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.

Related

Wix Toolset RegistrySearch is not saving a registry key

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.

MSIEXEC using command line REINSTALL not using original INSTALLDIR

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

Install to the common templates folder with wix

In the list of System Folder Properties provided by Windows installer, I see a TemplateFolder which is the "full path to the Template folder for the current user". So I can use TemplateFolder as the Directory ID in wix to install user-specific templates.
However, I need to install to the common templates folder, i.e. the one referred to as CSIDL_COMMON_TEMPLATES (also FOLDERID_CommonTemplates) in the windows API. Windows installer doesn't seem to provide a system folder property for this one.
How do I install files to the common templates folder with wix?
The documentation tells us on the "TemplateFolder"-ID that it depends on the installation context whether it is "the full path of the Templates folder for all users" (per-machine) or "the full path of the Templates folder for the current user" (per-user).
I ended up defining a COMMONTEMPLATEFOLDER like this:
<DirectoryRef Id='TARGETDIR'>
<Directory Id='COMMONTEMPLATEFOLDER' Name='Templates' />
</DirectoryRef>
<Property Id="COMMONTEMPLATEFOLDER">
<RegistrySearch Id="searchCommonTemplateFolder"
Root="HKLM"
Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
Name="Common Templates"
Type="raw" />
</Property>
This seems to work fine, but unfortunately it relies on undocumented registry entries. I would still like to find a better way.

WiX Property: Directory Search: "Could not access network location"

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!

WiX: How do you write variables specified on installation to the current user registry key of ALL users?

OS: MS Windows XP Pro (SP3)
My application needs to access external databases, the locations of which I specify on installation. The specified file paths are then written to the registry, and the application then pulls this information out of the registry when it needs to. I have implemented this in WiX as follows, using just one of the file paths as an example:
1) I create a variable (for one of the file paths), called RootDir and give it a default string value of “C:\”
<?define RootDir="C:\"?>
2) I insert an extra dialog in the installation UI and have an edit box (among others) which will display the default file path above.
<Dialog Id="FilePathDlg" Width="370" Height ="270" Title ="xxx">
<Control Id="RootDirEdit" Type="Edit" X="20" Y="72" Width="320" Height="18" Property="ROOTDIR" Text="[ROOTDIR]" />
3) I also have a component for creating the registry key where this string will reside
<Component Id="RegistryEntries" Guid="04AD0437-89E1-498c-85FF-EE180BEB53E0">
<RegistryKey Root="HKCU" Key="Software\xxx" Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Name="xxx" Value="[ROOTDIR]" KeyPath="yes"/>
</RegistryKey>
</Component>
When the installer is run, the user can edit the edit box described in (2) to enter the desired file path (say “P:\”). This value is saved to RootDir and then when the registry entries are installed, the value is written to the registry.
So far, so good. This works, but the problem is that it only writes the user-specified value (in this example “P:\”) to the registry entry in the current user key of the user performing the installation. Since I want the application to be installed by administrators only (I have a condition to do this), obviously the user-specified file paths are only written to the administrator’s current user key.
I have a line which ensures that the installation is per machine, rather than per user (i.e. the value of ALLUSERS is 1):
<Package InstallerVersion="300" Compressed="yes" Platform = "x86" InstallScope="perMachine"/>
So although the installer creates registry keys for all users, the value of the user-specified variable remains on the default value (in this case “C:\”) for all the other users but changes to the specified value (P:) for the administrator.
Does anyone know how I can change this so that the user-specified variables are written to the current user key registry entries of all the users rather than just those of the administrator?
Your installer should write to HKLM. Your app, on startup, should check for values in HKCU, and if they do not exist should be copied from HKLM.
There is a way but I highly advise against it. It relies on windows repair to propogate the HKCU registry component to each users profile the first time they use your application. Think along the lines of how many times you've seen Microsoft Office ask for the CDROM the first time you use the program.
This belongs in HKLM and you should rewrite your application to accept it there. Additionally there are those that would say that configuration data doesn't belong in an installer and that you should get it at first run of your application instead. I don't actually go that far in my believes but it's something for you to consider.