WiX installer: Installing to Appdata - Error ICE38, ICE64 & ICE91 - wix

I've been banging my head against this one for a while and I've finally caved (after a lot of searching) and have come to stack overflow for help.
As the title suggests I am trying to create an installer that can carry out a per-user install without requiring any elevated permissions.
However the following code generates a lot of ICE38 and ICE64 errors, as well as ICE91 warnings at compile time.
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="AppDataFolder">
<Directory Id="AppRootDirectory" Name="[Manufacturer]">
<Directory Id="INSTALLFOLDER" Name="[ProductName]" />
</Directory>
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="ATestProject" Level="1">
<ComponentGroupRef Id="modules" />
</Feature>
"modules" refers to the contents of a heat.exe generated .wxs file whose components install directory is "INSTALLFOLDER"
The solutions available on the internet indicate a lot of editing of my modules.wxs file in order to get this to work, this is not acceptable - There are well over 1000 files in this release process and anything that cannot be automated (done on the command line at build time or with a script) is entirely out of the question.
Thanks in advance!

You can set up a per-user install that, by default on windows 7 and later, installs to %localappdata%\Programs by doing the following;
<Property Id="ALLUSERS" Secure="yes" Value="2"/>
<Property Id="MSIINSTALLPERUSER" Secure="yes" Value="1" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="AppRootDirectory" Name="Manufacturer">
<Directory Id="INSTALLFOLDER" Name="ProductName" />
</Directory>
</Directory>
</Directory>
<!-- ... -->
<!-- ... -->
<Feature Id="ProductFeature" Title="ATestProject" Level="0">
<ComponentGroupRef Id="modules" />
</Feature>
Basically Setting the two properties at the top configures the installer to a "per user" install, which is UAC friendly and does not need elevated permissions.
See This for a detailed explanation.
Please also note that ProgramFilesFolder becomes %localAppData%/programs - Microsoft's default storage place for per-user applications and installing to a users profile rather than C:\Program Files (x86)\

Related

How to set Wix Property from UI which user can change during installation?

I have Wix Code which simply installs a txt file in the given location
The target location is enclosed in a Property THISONE
<Fragment>
<Property Id="THISONE" Value="C:\MyFolder"/>
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='APPLICATIONFOLDER' ComponentGuidGenerationSeed="{75266e3e-3781-47e3-ac29-46a2d90548f9}">
<Directory Id='MyFolder' Name='MyFolder'/>
</Directory>
</Directory>
<SetDirectory Id='APPLICATIONFOLDER' Value='[THISONE]' />
</Fragment>
<Fragment>
<Component Id="Component1" Directory="MyFolder" Win64="yes">
<File Id="FirstFile.txt"/>
</Component>
</Fragment>
I want a minimal UI with maybe just a textbox where I can edit the property value so that I can change the target installation file path.
How can I achieve that ?
Thanks in Advance
The WiXUIInstallDir may be what you want, as described in the WiX documentation.
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='APPLICATIONFOLDER' ComponentGuidGenerationSeed="{75266e3e-3781-47e3-ac29-46a2d90548f9}">
<Directory Id='MyFolder' Name='MyFolder'/>
</Directory>
</Directory>
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONFOLDER" />
<UIRef Id="WixUI_InstallDir" />
You must set the value of the property WIXUI_INSTALLDIR to the value of the ID of the directory you want the user to be able to specify the location of, as shown above. This is then passed to the WixUI_InstallDir dialog. Note that the directory ID must all be uppercase.
If you're using Visual Studio, you'll need to add a reference to WixUIExtension to your WiX project. See here for more details.

Two feature in different locations

I am trying to make a wix installer.
i have two features defined. I want to be able to install each feature in a different location.
<Feature Id='ServerInstallation' Title='Engine' Level='1' ConfigurableDirectory='TARGETDIR'>
<ComponentGroupRef Id='ServerFileSystemGroup' />
<ComponentGroupRef Id='RegistryGroup' />
</Feature>
I want to be able to put this anywhere on disk, with the default value c:\Program Files\ProductName\Feature1
<Feature Id='ClientInstallation' Title='Moduletitle' Level='1' ConfigurableDirectory='INSTALLLOCATION'>
<ComponentGroupRef Id='ClientSystemGroup' />
<Feature Id='Subfeatureid' Title='Subfeature' Level='1'>
<ComponentGroupRef Id='SubfeatureSystemGroup' />
</Feature>
</Feature>
I want to be able to put this anywhere on disk, with the default value c:\Program Files\ProductName\Feature2
But the two feature should be able to be installed in any non-related location.
I tried to define a root directory TARGETDIR and on the same level an INSTALLLOCATION but i get an error
The Directory with Id 'INSTALLLOCATION' is not a valid root directory. There may only be a single root directory per product or module and its Id attribute value must be 'TARGETDIR' and its Name attribute value must be 'SourceDir'.
How can i setup this properly?
It might help to see your <Directory> structure, but in any case, you can't use TARGETDIR as a configurable directory. TARGETDIR can only be used at the root, and everything goes inside.
I think yours should look something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ProductFolder" Name="ProductName">
<Directory Id="INSTALLDIR1" Name="Feature1" />
<Directory Id="INSTALLDIR2" Name="Feature2" />
</Directory>
</Directory>
</Directory>
Then you can use INSTALLDIR1 and INSTALLDIR2 for your ConfigurableDirectorys.
See also
http://robmensching.com/blog/posts/2010/1/26/stackoverflow-what-does-namesourcedir-refer-to/
http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Configurabble-Install-Directory-td5351039.html

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.

How to create a directory in Wix on D:

Using WiX 3.7, I have figured out how to create a folder in the root. This
<Directory Id="ReceivedFilesDir" Name="ReceivedFiles">
<Component Id="ReceivedFilesComponent" Guid="84A264EF-2BC5-41e3-8124-2CA10C2805DB">
<CreateFolder Directory="ReceivedFilesDir">
<Permission User="Administrators" GenericAll="yes" />
</CreateFolder>
</Component>
</Directory>
creates a folder C:\ReceivedFiles
I want it to be at D:\ReceivedFiles instead.
How do I achieve that?
I have played around with the DiskId attribute, but it did not seem to do anything.
Also, I don't want to change the whole installation folder, the ordinary part of the installation will still be below C:\Program Files (x86). I just want to create additional folders on D:.
Here's the solution we used for basically the same need:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CROOT" Name="root">
<Directory Id="MY_CROOT" Name="PLACE_HOLDER">
<!-- Define C directory -->
</Directory>
</Directory>
<Directory Id="TROOT" Name="root">
<Directory Id="MY_TROOT" Name="PLACE_HOLDER">
<!-- Define T directory -->
</Directory>
</Directory>
</Directory>
<CustomAction Id="SetCRootDirectory" Property="CROOT" Value="C:\" />
<CustomAction Id="SetTRootDirectory" Property="TROOT" Value="T:\" />
<InstallExecuteSequence>
<Custom Action="SetCRootDirectory" Before="AppSearch" />
<Custom Action="SetTRootDirectory" Before="AppSearch" />
</InstallExecuteSequence>
You could add this to a UI sequence if your install takes advantage of that. You may need to set the Custom Action Before values to some other value given how all the rest of your sequences are defined. Hope this is useful.

WiX merge module dependencies

I have an issue with some existing installers which I have repeated in a simple test case as follows:
Installer1 installs App1 and LibraryA(v1).
Installer2 installs App2, LibraryA(v2) and LibraryB. LibraryA(v2) requires LibraryB, which is why LibraryB is now installed. LibraryA(v1) had no such dependency. LibraryA(v2) should overwrite LibraryA(v1).
If I run Installer1 then Installer2, then uninstall Installer2, LibraryB gets removed, but LibraryA remains at v2 (sensible - I wouldn't expect it to revert to a prior version).
Forgetting my existing problem and imagine I was starting from scratch, how would you suggest I construct my WiX project to cope with such a situation? In my case, all of the libraries are defined as merge modules - something I'm not in a position to change (wixlibs are out of the question).
I have tried, to no effect, to use a Dependency element to create a dependency between the LibraryA(v2) merge module and the LibraryB merge module - it just seems to issue a linker warning if I forget to reference LibraryB in the installer, rather than creating an actual dependency.
The .wxs scripts in my test case look something like this (they all install to the same folder for ease of testing):
LibraryA(v1).wxs:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="LibraryAComponent" Guid="d98dd742-c3d3-4aee-8d84-87f2b3c837dc">
<File Source="v1\LibraryA.dll" />
</Component>
</Directory>
</Directory>
LibraryA(v2).wxs:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="LibraryAComponent" Guid="d98dd742-c3d3-4aee-8d84-87f2b3c837dc">
<File Source="v2\LibraryA.dll" />
</Component>
</Directory>
</Directory>
<Dependency RequiredId="LibraryBMergeModule.DD524F28_EAE0_47B8_A895_3AF2F7A7361A" RequiredLanguage="1033"/>
LibraryB.wxs:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="MergeRedirectFolder">
<Component Id="LibraryBComponent" Guid="46e6e0da-2a99-4f0d-bed2-e764e16b9eed">
<File Source="LibraryB.dll" />
</Component>
</Directory>
</Directory>
App1.wxs:
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" DiskId="1" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="WiXTest" Name="WiXTest">
<Merge Id="LibraryAv1" Language="1033" SourceFile="LibraryAv1.msm" />
<Component Id="App1Component" Guid="93D11AFF-5307-4355-B261-0096775B6A89">
<File Source="App1.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Libraries" Title="Shared Files" Level="1">
<MergeRef Id="LibraryAv1" />
</Feature>
<Feature Id="App" Title="Application" Level="1">
<ComponentRef Id="App1Component" />
</Feature>
App2.wxs:
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" DiskId="1" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="WiXTest" Name="WiXTest">
<Merge Id="LibraryB" Language="1033" SourceFile="LibraryB.msm" />
<Merge Id="LibraryAv2" Language="1033" SourceFile="LibraryAv2.msm" />
<Component Id="App2Component" Guid="173C71B6-E403-4AC1-894D-06799C6782A4">
<File Source="App2.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Libraries" Title="Shared Files" Level="1">
<MergeRef Id="LibraryB" />
<MergeRef Id="LibraryAv2" />
</Feature>
<Feature Id="App" Title="Application" Level="1">
<ComponentRef Id="App2Component" />
</Feature>
I'm guessing that this is entirely the wrong way to go about things and am looking for some pointers to bring me back on track. It feels like you need to have a PhD in Windows Installer in order to use WiX correctly.
I am no WIX expert but yes for MSI you need at least a PhD. At first you should know the rules about MSI components:
What Every Developer Should Know About MSI Components
From painful experience I do know that if several MSIs bring in the same components it is no good. If possible I would strive for the single source principle so that your libs are installed always by the same MSI (let it be a infrastructure MSI). Your application MSIĀ“s then simply check if the infrastructure has been installed and that was it.
Coming back to your question what you should do with your merge modules. I would create for each merge module an extra msi (yes customers do not like crowed installed software catalogs) to be sure that if you are in need to service the libraries you have full freedom.
I do not know your software structure but it could be that you will need LibraryA v1 and v2 at the same time so you should think about deploying your libraries to the WinSxS cache or if they are managed the GAC. Or you come up with something similar in your folder structure or file name convention.