I am struggling with Wix installer. During the install, the INSTALLDIR is overridden to a custom folder (not in Program Files). When I uninstall, the INSTALLDIR and the TARGETDIR gets set to E:\ no matter what I do.
How do I fix this? Here are the relevant snippets:
<Property Id="ARPINSTALLLOCATION">
<RegistrySearch Id="GetINSTALLDIRFromRegistry" Root="HKLM"
Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductCode]" Name="InstallLocation" Type="raw" />
</Property>
<SetDirectory Id="TARGETDIR" Value="[ARPINSTALLLOCATION]">Installed</SetDirectory>
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CreateFolders" Sequence="execute">NOT Installed</SetProperty>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" Name="WinApp">
</Directory>
</Directory>
</Fragment>
Thanks in advance. I am using Wix Tools 3.10.
Update 1
Here are my findings (for now. please correct me as I am still new to Wix)
Contrary to popular belief, the installer does not seem to set the install folders automatically during uninstall.
An important exception to the above rule is when the install folders are "well known" folders like ProgramFilesFolder.
So, If you set your directory structure to this:
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR">
<Directory Id="TEST" Name="WinApp" />
</Directory>
</Directory>
</Fragment>
You must set the INSTALLDIR directory through a property assignment or through a custom action. For example:
<Property Id="INSTALLDIR"><![CDATA[C:\mydir1\mydir1]]></Property>
If you set INSTALLDIR dynamically through a dialog box, you must read it from the registry or from a file (where you stored it during the install).
Update 2
Slightly improved version
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" Sequence="execute" After="InstallFiles" />
<Property Id="INSTALLDIR" Secure="yes">
<RegistrySearch Id="Locate_EXISTINGINSTALLDIR" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductCode]" Name="InstallLocation" Type="directory" />
</Property>
<CustomAction Id="SetTARGETDIR"
Directory="TARGETDIR"
Value="[INSTALLDIR]"
Return="check" />
<InstallExecuteSequence>
<!--this action launches a window to allow the user to choose the folder. don't want
to use standard MSI/Wix dialogs as the functionality is limited
-->
<Custom Action='SelectFolderCustomAction' Before='CreateFolders'>NOT Installed</Custom>
<!--<Custom Action='RegistrationInfoCustomAction' Before='InstallFinalize'>NOT Installed</Custom>-->
<!--<Custom Action='UninstallCustomAction' Before='RemoveFiles'>Installed AND REMOVE = "ALL"</Custom>-->
<Custom Action="SetTARGETDIR" Before="RemoveFiles">Installed AND REMOVE = "ALL"</Custom>
</InstallExecuteSequence>
I dont understand what you are trying to do above. Why are you reading the install location from the registry?
This is what I do for installing to "D:\Program Files" folder.
<Property Id="ROOTDRIVE"><![CDATA[D:\]]></Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles" Name="Program Files">
Remove the SetDirectory element, it's obsolete. When the product is already installed, Windows Installer automatically sets the directory properties to the pathes of the actual installation directories.
The RegistrySearch for ARPINSTALLLOCATION looks strange too. Normally this property should only be set during first install, which you already do by using the SetProperty element.
So the following should be enough:
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CreateFolders" Sequence="execute">NOT Installed</SetProperty>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" Name="WinApp"/>
</Directory>
</Fragment>
Related
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.
I’m beginning with WiX and I have some trouble to customize ExitDIalog.
At first what I want:
I want to create a setup for my application
After setup I want to propose 2 choices :
Launch application (application.exe newly installed)
Launch an optional setup (my application require to install some drive depending of user’s camera)
The optional setup is a .exe. It should be placed next to setup.msi but no copied in my application folder.
I created directories :
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="$(var.compagny)"/>
</Directory>
<Directory Id="DesktopFolder" SourceName="Desktop"/>
<Directory Id="ProgramFilesFolder">
<Directory Id="COMPAGNYFOLDER" Name="$(var.compagny)">
<Directory Id="INSTALLFOLDER" Name="$(var.product)">
<Directory Id="fr" Name="fr"/>
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
How can I add a reference to my .exe ? I did :
<Component Id="ProductComponent" Guid="{2C26B191-6654-4405-8E78-F8B6EFEDC9FC}" Directory="INSTALLFOLDER">
<File Id="uEye64_47100_WHQLexe" Source="./Resources/uEye64_47100_WHQL.exe" KeyPath="yes" Checksum="yes" Compressed="no" Vital="no"/>
</Component>
But the uEye64_47100_WHQL.exe file is copied in INSTALLFOLDER (I don't want) and the setup mix the path with [application]/bin/Release (don't know with). In the log file there is :
Failed to open the file:C:\dev\MyApplication\main\SetupProject\bin\Release\MyCompagny\MyProduct\uEye64_47100_WHQL.exe for computing its hash. Error:3
And I call the .exe like this (this file require elevated privileges)
<!-- Set checkbox for launch install uEye -->
<Property Id="WIXUI_EXITDIALOGUEYECHECKBOXTEXT" Value="Launch install uEye"/>
<CustomAction Id="SetExecUEye" FileKey="uEye64_47100_WHQLexe" ExeCommand="" Return="asyncNoWait" Impersonate="no" Execute="deferred"/>
<UI>
<UIRef Id="WixUI_Custom"/>
<Publish Dialog="MyExitDialog"
Control="Finish"
Event="DoAction"
Value="SetExecUEye">WIXUI_EXITDIALOGUEYECHECKBOX = 1 and NOT Installed</Publish>
</UI>
How should I define my uEye64_47100_WHQL.exe to be called after setup but no copied in INSTALLFOLDER ?
If you don't want to copy file to install location, just run it, you can include it as Binary source instead of component. This way, it is packed in installer, but is not deployed on installation (probably to some temp folder only).
<Binary Id="uEye64_47100_WHQLexe" SourceFile="./Resources/uEye64_47100_WHQL.exe" />
<CustomAction Id="InstalluEye64exe" BinaryKey="uEye64_47100_WHQLexe" ExeCommand="" Execute="deferred" Return="ignore" Impersonate="no"/>
I get the error "could not access network location \Common" when running the installer.
Any ideas will be much appreciated.
<Property Id="BINDIR">
<RegistrySearch Id='BinDirReg' Type='raw' Root='HKLM' Key='SOFTWARE\xxx' Name='AppDir' Win64='no'/>
</Property>
<Property Id="DATADIR">
<RegistrySearch Id='DataDirReg' Type='raw' Root='HKLM' Key='SOFTWARE\xxx' Name='DataDir' Win64='no'/>
</Property>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<UIRef Id="WixUI_InstallDir" />
<SetDirectory Id="TESTBINFOLDER" Value="[BINDIR]\a\b\c" />
<SetDirectory Id="TESTDATAFOLDER" Value="[DATADIR]\a\b\c" />
<SetDirectory Id="TESTCOMMONDATAFOLDER" Value="[DATADIR]\Common" />
The value of the DATADIR property is empty so the value of TESTCOMMONDATAFOLDER is "\Common"
You really shouldn't be trying to define your Directory structure this way since on your very first install you'll try to set the TESTCOMMONDATAFOLDER to [DATADIR]\Common but there's no way your registry key exists in the registry.
You should define your Directory Structure as a default baseline. THere are several well-definied System Folder Properties for msis that you can use to define your default directory structure.
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="CompanyName">
<Directory Id="BIN" Name="_bin" />
<Directory Id="DataDir" Name="Data" />
</Directory>
</Directory>
<Directory Id="AppDataFolder" >
<Directory Id="ProductName" />
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="ProductName"/>
</Directory>
</Directory>
Define your default structure this way. If you let the user set a custom install location, you can use a registry search to set the property for the directory and everything else will update nicely. for example,
<Property Id="INSTALLDIR">
<RegistrySearch
Id="InstallDirRegSearch"
Root="HKLM"
Key="SOFTWARE\ProductName"
Name="Path"
Type="raw"/>
</Property>
And this will set the INSTALLDIR to the custom location and all the BIN and DataDir folders will get updated with the new INSTALLDIR location. You can do a similar registry search to set directory locations for all other Directories. The plus side of doing it this way is that if these registry locations do not exist, you'll still use the default defined structure for your installation.
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.
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)\