WIX toolset: Store (configurable) Install directory inside registry - wix

I am using the feature tree dialog set which allows for a customised install directory, I am then trying to store this install directory inside a registry
As per Wix's documentation I am defaulting the ui variable to the directory I want
<Property Id="WIXUI_INSTALLDIR" Value="VERSION" />
<SetProperty Id="VERSION" Value="[ProgramFilesFolder]Thermo\SampleManager\[PROP_VERSION]" After="CostInitialize" />
Then trying to set the registry as follow
<RegistryKey Root="HKCR" Key="x\x\x">
<RegistryValue Type="string" Value="[VERSION]aaasx\aasx" />
</RegistryKey>
Obviously the [VERSION] does not change with the UI selection, which variable should I be using to change the configured directory? Feel as if I've tried every suggested [INSTALLDIR] etc.
Directory is configured as such
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="COMPANY" Name="Company">
<Directory Id="PRODUCT" Name="Product">
<Directory Id="VERSION" Name="Version">
Further investigation found that using file references ( [#file] ) works, which solves 90% of my problems, however pointing/storing a directory path does not work

You can use only RegistryValue like that:
<RegistryValue Root='HKCR' Key='SOFTWARE\MyProcudt'
Name='MyPath' Value='[INSTALLDIR]'
Type='string' />
It will create registry in HKCR/software/myproduct name "mypath" with value [installdir] (set ealrier).

Related

WIX - howto use RemoveFolderEx with On="install" / "both"?

I am trying to remove a folder on "install" (and "uninstall"), but the folder is only removed on "uninstall".
Any hints how this can be done?
<Property Id="PACKAGEFOLDER">
<RegistrySearch Root="HKLM" Key="$(var.RegKey)" Type="raw" Id="PKGFOLDER_REGSEARCH" Name="PkgDir" />
</Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="PACKAGE" Name="$(var.PkgFolder)">
<Component Id="PackagesFiles" Guid="$(var.FilesGUID)">
<RegistryValue Root="HKLM" Key="$(var.RegKey)" Name="PkgDir" Type="string" Value="[PACKAGE]" KeyPath="yes" />
<util:RemoveFolderEx On="both" Property="PACKAGEFOLDER" />
</Component>
</Directory>
</Directory>
</Directory>
just noticed:
if the RegKey is available in registry before installation starts, it will work:
WixRemoveFoldersEx: Recursing path: C:\Program Files (x86)... for
row: wrf945C37509CA5EEDC2367957D5F072DFF. MSI (s) (94!A8)
[19:17:55:185]: PROPERTY CHANGE: Adding _UNOPACKAGEFOLDER_0 property.
Its value is 'C:\Program Files (x86)... MSI (s) (94:D4)
[19:17:55:185]: Doing action: CostInitialize
but if the RegKey is not in registry, log says:
WixRemoveFoldersEx: Error 0x80070057: Missing folder property:
APPLICATIONFOLDER for row: wrfA308D08284221970F6338358BFB75917
CustomAction WixRemoveFoldersEx returned actual error code 1603 but
will be translated to success due to continue marking MSI (s) (84:50)
[19:29:08:529]: Doing action: CostInitialize
Is it possible to write the RegKey before the Property "PACKAGEFOLDER" is set?
I assume that you have also files in this folder that should be deleted. If there are no (arbitrary) subdirectories containing files it should be straight forward by using the RemoveFile-table of the Windows Installer. As it will only delete the folder if it is empty, add an additional entry that will delete the files in it, e.g.:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="PACKAGE" Name="$(var.PkgFolder)">
<Component Id="PackagesFiles" Guid="$(var.FilesGUID)">
<RegistryValue Root="HKLM" Key="$(var.RegKey)" Name="PkgDir" Type="string" Value="[PACKAGE]" KeyPath="yes" />
<RemoveFile Id="RemovePACKAGEFolderFiles" Directory="PACKAGE" Name="*.*" On="both" />
<RemoveFolder Id="RemovePACKAGEFolder" Directory="PACKAGE" On="both" />
</Component>
</Directory>
</Directory>
</Directory>
This way you don't have to deal with any property setting. If you have other subdirectories with files you would have to repeat this also for these.
Another way would be to create a deferred custom action in the system context that will delete the folder completely, e.g. in VBScript.
If you add
<SetProperty Id="PACKAGEFOLDER" Value="[PACKAGE]" After="CostFinalize" />, you can get the value of package during install. From this article regarding property-setting.

Wix - Setting Install Folder correctly

I'm creating a program which is being installed by Wix, using VS 2010 and I've already got the product.wxs ready.
In my wxs file, I've got directory definitions which looks like this:
<SetDirectory Id="INSTALLFOLDER" Value="[WindowsVolume]Myapp" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="Myapp_Installer_Dir" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And then I got these file installation definitions:
<DirectoryRef Id="Myapp_Installer_Dir">
<Component Id="INSTALLER_Myapp" Guid="{94F18477-8562-4004-BC6F-5629CC19E4CB}" >
<File Source="$(var.Myapp.TargetPath)" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="BIN">
<Component Id="INSTALLER_Data" Guid="{545FB5DD-8A52-44D7-898E-7316E70A93F5}" >
<File Source="$(var.Data.TargetPath)" KeyPath="yes"/>
</Component>
...
And it continues in that manner. The files for the "ICONS" directory are defined as well.
I am also using the WixUI_InstallDir dialog set and I got these lines present as well:
<Property Id="WIXUI_INSTALLDIR" Value="Myapp_Installer_Dir" />
<UIRef Id="WixUI_InstallDir" />
The problem is when the user installs the program and changes the value of the installation folder, the files of the "Bin" and "Icons" are installed to their correct path, but the Myapp target is installed to a fix location which was defined at the start as the default installation path.
Why do only the bin and icon files installed to the correct folder the user wanted, but the myapp target does not?
I have finally figured out the problem.
After searching for a while, I came across this document:
WixUI_InstallDir Dialog Set
The relevant part: "The directory ID must be all uppercase characters because it must be passed from the UI to the execute sequence to take effect."
And as you can see in my code: "Myapp_Installer_Dir" does not meet this criteria.
After changing it to "MYAPPINSTALLERDIR", everything worked.
I'm not quite sure, but this is what I think has happened.
When you author a SetDirectory element, you basically add a custom action which sets a directory to the MSI database. As long as you do not specify the sequence it is executed in, it defaults to both, which means execute in both InstallUISequence and InstallExecuteSequence.
Now, when a user changes the installation directory in the wizard, this happens in the UI sequence. Obviously, when the installation enters the execute sequence, the value of INSTALLFOLDER is set to [WindowsVolume]Myapp as it was instructed.
So, you have to rework this somehow. Keep in mind the silent installation as well - there's only execute sequence there.
UPDATE instead of what you have, try something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsVolume">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And let the user optionally change the INSTALLFOLDER as you do now.
Additionally to the pitfall with capital letters there is also an other one:
You have to mark the ID of the changeable directory as secure. (At least when the setup runs with admin rights.)
Related to Yonatan's answer with the directory ID MYAPPINSTALLERDIR you have to add this:
<Property Id="MYAPPINSTALLERDIR" Secure="yes" />
Related to the example WixUI_InstallDir in the WiX documentation you have to add this:
<Property Id="TESTFILEPRODUCTDIR" Secure="yes" />
Unfortunately this important fact is not mentioned in the WiX example.

Changing folder on major upgrade

I have a default directory for installation:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="$(var.Manufacturer) $(var.ProductName)"></Directory>
</Directory>
</Directory>
During installation, I allow users to change directory. If a user does change directory during major upgrade, do I have to retrieve the directory manually and set INSTALLFOLDER with actual path or is there a way to detect it automatically somehow?
This is not supported by Windows Installer directly; I think you're looking for the "remember property" pattern. The strategy is:
On initial installation, save the value of INSTALLFOLDER to the registry in a well-known location.
When starting an upgrade, retrieve the value from the registry and use it.
The authoring looks like this:
<!-- Retrieve the property from the registry during AppSearch -->
<Property Id='REMEMBERME'>
<RegistrySearch Id='RememberProperty'
Root='HKCU'
Key='SOFTWARE\My Company\My App'
Name='Remembered'
Type='raw' />
</Property>
<!-- Save the value in the registry for future upgrades -->
<Component Directory='INSTALLFOLDER'>
<RegistryValue Root='HKCU'
Key='SOFTWARE\My Company\My App'
Name='Remembered'
Value='[REMEMBERME]'
Type='string' />
</Component>
Rob Mensching's blog post describes this in much more detail.

Register add-ins, project templates and item templates for Visual Studio 11

I've been using Wix 3.5 with WixVSExtension to install project item templates for Visual Studio 2010, Visual C# 2010 Express and Visual Web Developer 2010 Express. I'd like now to add support for Visual Studio 11 Beta.
I added registry search and custom actions to find the VS11 installation folders but, when specifying directory and components structure, I'm getting compilation errors like this one:
error LGHT0204: ICE30: The target file 'ewa5nwrn.zip|BasicApplication.zip' is installed in '[TARGETDIR]\CSharp\' by two different components on an LFN system: 'VS2010CSharpProjectTemplates' and 'VS11CSharpProjectTemplates'. This breaks component reference counting.
I have this directory structure:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="VS2010_PROJECTTEMPLATES_DIR">
<Directory Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
<Directory Id="VS11_PROJECTTEMPLATES_DIR">
<Directory Id="VS11_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
Notice that I have VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR inside TARGETDIR. The error message shows that they are ignored.
The components are defined as follow:
<DirectoryRef Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR">
<Component Id="VS2010CSharpProjectTemplates" Guid="{0976A222-8243-40F2-81AB-84D8F1771840}" Transitive="yes">
<File Id="VS2010BasicApplication" Source="BasicApplication.zip" />
</Component>
</DirectoryRef>
<DirectoryRef Id="VS11_PROJECTTEMPLATES_CSHARP_DIR">
<Component Id="VS11CSharpProjectTemplates" Guid="{A70428F1-AE26-4B07-9F58-D67587B44657}" Transitive="yes">
<File Id="VS11BasicApplication" Source="BasicApplication.zip" />
</Component>
</DirectoryRef>
Is it possible to install the same file into two different directories specified by properties?
Thanks in advance,
aalmada
I don't have any source code to share but I can tell you in general how I've done this in the past.
We decided to "install" the zip files to our main application directory in a Integration folder so that the files would always be available even if VS2008 and/or VS2010 had not been installed at the time of installation. I then used a bunch of built-in properties that exist in the Util extension and a couple custom RegLocator searches to define a bunch of properties related to the location of devenv.exe and ItemTemplate, ProjectTemplates and other directories that we needed in .NET. I then used those properties in CopyFile elements so that MSI would duplicate those files in the Integration folder to the actual VS directories as needed and approriate. Finally I used the WiX QuietExec custom action to call Devenv /setup to register the content with VS. I also used the ProgressText element ( ActionText table ) to make the UI look good while this was all happening as VS devenv can take awhile.
As explained in the wix documentation of the Directory element: when you omit the Name attribute you are creating an alias for the parent Directory element.
This is done by recording "." as the directory name in the installer database, as explained in the windows installer documentation for the Directory table.
In your case, I believe you attempt to change this "." value into a real directory name by setting the VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR properties (because directories are properties) during the installation.
That's fine, but the problem here is that the light linker doesn't know what values you will set these properties to during the installation. It only has the Name attribute value to work with. And at link time, it looks like you are installing the same file twice to the same directory.
To fix this, add Name attributes with different placeholder values to the VS2010_PROJECTTEMPLATES_DIR and VS11_PROJECTTEMPLATES_DIR directory elements.
I ended up adding two base directories, under TARGETDIR, with the Name properties set:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="VS2010" Name="VS2010">
<Directory Id="VS2010_PROJECTTEMPLATES_DIR">
<Directory Id="VS2010_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
<Directory Id="VS11" Name="VS11">
<Directory Id="VS11_PROJECTTEMPLATES_DIR">
<Directory Id="VS11_PROJECTTEMPLATES_CSHARP_DIR" Name="CSharp">
</Directory>
</Directory>
</Directory>
</Directory>
Here is the code for the properties (based on the WixVSExtension code):
<Property Id="VS11DEVENV" Secure="yes">
<RegistrySearch Id="VS11DevEnvSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentPath" Type="raw"/>
</Property>
<Property Id="VS11_ROOT_FOLDER" Secure="yes">
<RegistrySearch Id="SearchForVS11RootPath" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\SxS\VS7" Name="11.0" Type="raw"/>
</Property>
<Property Id="VS11_PROJECTTEMPLATES_DIR" Secure="yes">
<RegistrySearch Id="VS11DevEnvForProjectTemplatesSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentDirectory" Type="raw">
<DirectorySearch Id="VS11ProjectTemplatesPathSearch" Path="ProjectTemplates" Depth="1" />
</RegistrySearch>
</Property>
<Property Id="VS11_ITEMTEMPLATES_DIR" Secure="yes">
<RegistrySearch Id="VS11DevEnvForItemTemplatesSearch" Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS" Name="EnvironmentDirectory" Type="raw">
<DirectorySearch Id="VS11ItemTemplatesPathSearch" Path="ItemTemplates" Depth="1" />
</RegistrySearch>
</Property>
<CustomAction Id="VS11InstallVSTemplates" Property="VS11DEVENV" ExeCommand="/InstallVSTemplates" Execute="deferred" Return="ignore" Impersonate="no" />
I then found out that the VS2010 templates don't expand correctly under VS11 but that's a different question now... :-/

bad install directory path

I am creating a setup project in WiX, I've used WixUI_Common as a base and extended it with my custom dialogs. But when the user gets to the InstallDirDlg dialog, the installation path is "C:\", and this is totally unacceptable. Although previously in the code I've set:
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="Component_SetupCM.wxs" Guid="60A58B24-CA71-44CE-947F-6BBDC7C6C89C" >
<File Source="Product.wxs" Id="Product.wxs" KeyPath="yes"/>
</Component>
</Directory>
<Property Id="WIXUI_INSTALLDIR" Value="TARGETDIR" />
So what could be the problem?
you need something like this:
<DirectoryRef Id = TARGETDIR>
<Directory Id = "ProgramFilesFolder">
<Directory Id = "INSTALLDIR" Name = "MyAppName"/>
</Directory>
</Directory>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
The problem you are have is that TARGETDIR = c:\
UPDATE:
As long as you have the line
<Property Id="WIXUI_INSTALLDIR" Value="TARGETDIR" />
You will continue to have the same problem. TARGETDIR = c:\ and it always will.
Notice in my example I set WIXUI_INSTALLDIR to INSTALLDIR and not TARGETDIR. The problem with your code was not the directory structure so much as that you were setting WIXUI_INSTALLDIR to the wrong value. My solution above works as I copied it from a project I'm currently using.