Values of multiple PathEdit controls to multiple properties - wix

I want to build an Installer with Microsoft Wix 3.8 that actually just registers some COM-components and creates some shortcuts to a program on a server share. Just to point that out in advance: This program is a legacy tool and the way it's launched or used won't be changed, unfortunately.
So I need my installer to ask for three paths: The server installation path (as unc), and two additional paths, also on the server (also as unc).
I'm already struggling with the first path. As soon as I add it it seems to be hard wired to some directory I have to specify in my product.wxs.
That's how my product.wxs looks like:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
<Product Id="613A5421-BF59-46DD-B363-05E55587B89F" Name="Test Client" Language="1033" Version="1.0.0" Manufacturer="Blub AG" UpgradeCode="A451E5EB-4AED-4A8A-ACBC-F65A34E86D45">
<Package Id="*" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MediaTemplate />
<WixVariable Id="WixUIDialogBmp" Value="images\background.bmp" />
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<UIRef Id="WixUI_InstallDir" />
<Feature Id='Complete' Title='Foobar 1.0' Description='The complete package.'>
<Feature Id='TestClient' Title='Test Client' Description='Test Client' Level='1'>
<ComponentGroupRef Id='ProductComponents' />
</Feature>
</Feature>
</Product>
<Fragment>
<PropertyRef Id="NETFRAMEWORK20"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="ExpoWin" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER" >
<Component Id="ProductComponent">
<File Source="Blub.txt" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
(In my original code I replaced the WixUI_InstallDir with my own version so that I can modify it to ask for three paths. But to point out my problem the code above should suffice)
I don't want the "INSTALLFOLDER" to be linked to any Directory. But as soon as I change
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
to
<Property Id="WIXUI_INSTALLDIR" Value="SERVERPATH" />
<Property Id="INSTALLFOLDER" Value="c:\program files (x86)\TestClient" />
and run the installer I get a "2343 error":
DEBUG: Error 2343: Specified path is empty.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2343. The arguments are: , ,
Well hopefully this question is easy to answer. I've been searching the web for hours. Probably I haven't understood the concept of properties entirely. Can someone shed some light on this?

The following explanation might not be valid 100%, it's the way that I explain it to myself ;-).
WiX takes the value of a property and uses it to resolve the path. In the first case it finds the property in the directory structure, so the path can be resolved. In the second example SERVERPATH is just the string SERVERPATH, so it can't find anything. You have to either set it using a registry search or to a concrete path or by a custom action.
What worked great for me in the UI and custom dialogs (I had a similar requirement with the installation folder and an additional path) was the answer to a similar question.
Here is an example for setting it via a custom action (INSTALLLOCATION in my case was read from the registry, but it can be any path; INSTALLDIR is defined by the directory structure in the WiX source file):
<CustomAction Id="SetINSTALLDIR" Property="INSTALLDIR" Value="[INSTALLLOCATION]" Execute="firstSequence" />
<InstallExecuteSequence>
<Custom Action="SetINSTALLDIR" After="AppSearch">INSTALLLOCATION</Custom>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="SetINSTALLDIR" After="AppSearch">INSTALLLOCATION</Custom>
</InstallUISequence>
Using the method described in the answer above I have the following in my WiX source file:
<Directory Id="LUCENEFOLDER" SourceName="LuceneIndex" />
The path is then set in the UI on a custom dialog by the following snippet:
<Control Id="LuceneFolderLabel" Type="Text" X="5" Y="155" Width="200" Height="10" Text="Folder containing Multiindex.config of Lucene:" TabSkip="yes" />
<Control Type="PathEdit" Id="LuceneFolder" Width="200" Height="17" X="5" Y="165" Property="LUCENEFOLDER"/>
<Control Id="LuceneFolderBrwsButton" Type="PushButton" Width="56" Height="17" X="210" Y="164" Text="Change..." >
<Publish Property="_BrowseProperty" Value="LUCENEFOLDER" Order="1">1</Publish>
<Publish Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
</Control>

Related

Wix icon in Add/Remove programs

I am using Wix to create my installer.
According to the official documentation, if I want to change the icon in Add/Remove Programs, I need to add this:
<Icon Id="icon.ico" SourceFile="MySourceFiles\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
But it does not works, the icon is not changed and I also get the following warning:
C:\Users\rsheink\home\repos\tenlira\10Lira\TestWiXProject\Product.wxs(137,0):
warning LGHT1076: ICE36: Icon Bloat. Icon icon.ico is not used in the
Class, Shortcut, or ProgID table and also not used for ARPPRODUCTICON
property.
What am I missing please?
Thanks. Refael.
Edit:
Following the excelent advice from #harper, here is the MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:difx="http://schemas.microsoft.com/wix/DifxAppExtension">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Intel Corporation"
Name="TenLira" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Your local administrator" Description="TenLira" InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Intel Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="no"
AllowSameVersionUpgrades="no"
Disallow="no"
IgnoreRemoveFailure="no"
MigrateFeatures="yes"
Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Intel Corporation">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="TenLira">
<Directory Id="kmgl" Name="kmgl">
<Directory Id="kmgl_win10" Name="kmgl_win10" />
</Directory>
<Directory Id="tools" Name="tools" />
</Directory>
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="tools">
<Component Id="devcon.exe" Guid="*">
<File Id="devcon.exe" Source="..\tools\devcon\amd64\devcon.exe" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="devcon.exe" />
</Feature>
<!--It should set the icon in Add/Remove programs, but it does not works and I don't know why.-->
<Icon Id="icon.ico" SourceFile="..\TenLira icons\coins\coins.ico" />
<Property Id="ARPPRODUCTION" Value="icon.ico" />
</Product>
</Wix>
Request: Please comment if any of the below works for you - and also if you did something else (as well) to get things working.
Quick List First:
Is ARPPRODUCTICON spelled correctly?
Does the File.ico file have a hidden file extension? Example: icon.ico.bmp - 1.
Show file extensions in Windows Explorer
Open a cmd.exe in the folder and do a dir to check?
Icon file problems:
Is that a proper *.ico file? Try to save a normal *.bmp and rename the extension to *.ico. That should work for a rudimentary test icon.
Find a proper template *.ico file for testing (there should be plenty
in your Visual Studio installation folder).
UPDATE:
Please try to change this:
<Property Id="ARPPRODUCTION" Value="icon.ico" />
into this:
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
I will leave the original answer below since the setup.exe issue might be relevant for others.
And one more thing: I was told that the dialog set <UIRef Id="WixUI_Mondo" /> is the better one in the available WiX templates. I have no hard facts apart from that recommendation though. I haven't used <UIRef Id="WixUI_InstallDir" /> - just if it can save you some time.
Old Answer:
This might just be a uppercase / lowercase issue. As in icon.ico instead of Icon.ico.
Correct:
<Icon Id="Icon.ico" SourceFile="MySourceFiles\Icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="Icon.ico" />
Wrong:
<Icon Id="icon.ico" SourceFile="MySourceFiles\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="Icon.ico" />
During my testing I get the warning though, but the icon does work in Add/Remove Programs either way. Are you making a setup.exe bundle?
When you make a setup.exe bootstrapper bundle, you have to set the IconSourceFile attribute of the Bundle Element.
A link for safekeeping: How to customize icon for Wix custom bootstrapper.

Updating WIX transformations

I'm trying to create an installer (using WIX 3.11) which can install more instance's of the same program. I have managed to create an installer which does that, but the installer does not work when trying to do an update of the different instances
Here's my code
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Name="ABC Default" Manufacturer="Inc" Language="1033" Version="1.0.1.7"
Id="*"
UpgradeCode="{3984A5B2-5CDA-4EC8-933A-089E46E2D688}">
<Package Id="*" InstallerVersion="200" Compressed="yes" InstallScope="perMachine"
Keywords="Installer" Description="Installer"
Comments="Instance installer" Manufacturer="Me"
Platform="x64"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<UI>
<UIRef Id="WixUI_InstallDir" />
<!--Skip license dialog-->
<Publish Dialog="WelcomeDlg"
Control="Next"
Event="NewDialog"
Value="InstallDirDlg"
Order="2">1</Publish>
<Publish Dialog="InstallDirDlg"
Control="Back"
Event="NewDialog"
Value="WelcomeDlg"
Order="2">1</Publish>
</UI>
<MajorUpgrade AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize" DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<MediaTemplate />
<Property Id="INSTANCEID" Value="0" />
<InstanceTransforms Property="INSTANCEID" >
<Instance Id="DEV" ProductCode="*" UpgradeCode="{BB75B4BE-6217-4FDA-8BAC-C46B402AC0FB}" ProductName="ABC Dev" />
<Instance Id="TEST" ProductCode="*" UpgradeCode="{ACFEFC2F-0D48-4640-9BBC-6E1162F9D1E7}" ProductName="ABC Test" />
</InstanceTransforms>
<Feature Id="ProductFeature" Title="Products" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<CustomAction Id="SetInstanceDirectory"
Property="InstanceDirectory"
Value="[INSTALLFOLDER][INSTANCEID]\"/>
<InstallExecuteSequence>
<Custom Action="SetInstanceDirectory"
Before="CostFinalize"><![CDATA[InstanceDirectory = ""]]></Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Inc" >
<Directory Id ="InstanceDirectory" Name="Instance"/>
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="InstanceDirectory">
<Component Id="NotepadComponent" Guid="{52BCDD67-47F3-4F04-A7F9-6CAB42010CDE}" MultiInstance="yes">
<File Source="c:\Windows\System32\notepad.exe"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
As can be seen the installer is quite simple, but I need some help on the updating part.
Install procedure:
msiexec /i test_installer.msi
msiexec /i test_installer.msi MSINEWINSTANCE=1 TRANSFORMS=":DEV"
/l*vx log.log
msiexec /i test_installer.msi MSINEWINSTANCE=1 TRANSFORMS=":TEST"
/l*vx log.log
Update procedure:
msiexec /i test_installer.msi
msiexec /i test_installer.msi TRANSFORMS=":DEV" /l*vx log.log
When trying to update the DEV instance, the installer tries to update the default installation informing the user that the installation is up-to-date and repair or uninstall are possible.
Please help. I have been looking at this problem for more than a week now.
/Kenneth
MSINEWINSTANCE=1 should be specified always, because your updates are provided as major upgrade.
I just had a look at some code that uses instance transforms. There is no distinction between first install and upgrade install, the command-line is always the same.
This makes sense as a major upgrade is like a new product installation, the only difference being that it automatically removes the older version.

WiX Installer : Single Package Authoring (per machine : not installing in program files)

I have the below Wix XML code that I have written for Single Package Authoring. The problem is when "Install for all unders of this machine" mode is selected in the UI(WixUI_Advanced), the default location that shows up in the UI is "C:\Users\XXXX\AppData\Local\Programs\MyApp\ ". How can I change this, so that the default location is ..\Program Files (x86)\MyApp....
If I change <Property Id="MSIINSTALLPERUSER" Value=" "/>,
then the default location is ..\Program Files(x86).., but the per user does not work due to lack of admin privileges.
Much appreciated.
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<!--Product Information-->
<Product Id="*"
Name="$(var.ApplicationName)"
Language="1033" Version="!(bind.FileVersion.$(var.ExecutableName))" Manufacturer="$(var.ManufacturerName)"
UpgradeCode="33bc2348-****-****-****-ebcde0d14afe">
<!--MSI Package Information-->
<Package InstallerVersion="500"
Compressed="yes" />
<!--Single Package Authoring-->
<Property Id="MSIINSTALLPERUSER" Value="1"/>
<Property Id="ALLUSERS" Value="2"/>
<!--Upgrade Information-->
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.ApplicationName) is already installed." />
<MediaTemplate EmbedCab="yes" />
<!--Application Features-->
<Feature Id="CoreFeature" Title="$(var.ApplicationName)" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id="ApplicationShortcut" />
<ComponentRef Id="RegisterApplicationAutoStart" />
</Feature>
<!--Required .NET Framework for the Application-->
<PropertyRef Id="NETFRAMEWORK35" />
<Condition Message="This application requires Microsoft .NET Framework 3.5 or greater. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR NETFRAMEWORK35]]>
</Condition>
<!--Advanced UI-->
<Property Id="ApplicationFolderName" Value="$(var.ApplicationName)" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<UIRef Id="WixUI_Advanced"/>
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<!-- Define the Target Directory. The individual files will be filled in via a Heat generated fragment. -->
<Directory Id="TARGETDIR" Name="SourceDir">
<!--Define the directory when the application will be installed-->
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="$(var.ApplicationName)" />
</Directory>
</Fragment>
<Fragment>
<Component Id="RegisterApplicationAutoStart" Directory="ApplicationProgramsFolder" Guid="*">
<RegistryValue Root="HKMU"
Key="Software\Microsoft\Windows\CurrentVersion\Run"
Name="$(var.ApplicationName)"
Type="string"
Value="[APPLICATIONFOLDER]$(var.ExecutableName)"
KeyPath="yes" />
</Component>
</Fragment>
</Wix>
The OP described it perfectly. With single authoring enabled in the following way, there seems to be no way to obtain to "actual" ProgramFilesFolder at C:\Program Files (x86)\.
<Package InstallerVersion="200" ... /> <!-- do not specify InstallScope or InstallPrivileges! -->
<Property Id="ALLUSERS" Value="2" />
<Property Id="MSIINSTALLPERUSER" Value="1" />
Even if MSIINSTALLPERUSER is reset, this does not change the value of ProgramFilesFolder, it's still C:\Users\XXX\AppData\Local\Programs (I assume the folder is initialised through SHGetFolderPath at installer startup, and doesn't change thereafter).
Setting the ProgramFilesFolderexplicitly like the OP showed in his answer would work I guess, but it's an ugly hack. What worked for me in the end was to start out in 'perMachine'-Mode:
<Property Id="ALLUSERS" Value="2" />
<Property Id="MSIINSTALLPERUSER" />
Afterwards, if the installer chooses the 'perUser'-Mode, I set the variables accordingly:
<Publish Dialog="MyWelcomeDlg" Control="Next" Property="MSIINSTALLPERUSER" Value="1">1</Publish>
<Publish Dialog="MyWelcomeDlg" Control="Next" Property="ALLUSERS" Value="{}">1</Publish>
This way, the folders will be correctly set.
I consider the underlying problem to be that ProgramFilesFolder would ever get set to something in AppData, that makes little to no sense.
If you want to install to the Program Files folder then you are required to be administrator. Limited users cannot create or update files in that folder, and running an MSI install does not break security just because it's an install. So the answer is that you cannot install to ProgramFiles unless you cause the MSI to ask for elevated privileges. Your question is essentially "how can a limited user break security by adding or replacing files in the Program Files folder", and there's no way to answer that.
Does your app require elevated privileges to run? Does it have an elevation manifest? If the answer is yes, then I suspect you're stuck with the requirement that elevated privileges are also needed to install it.
I included the below line in the WiX installer that fixed my issue.
<SetDirectory Id="ProgramFilesFolder" Value="C:\Program Files (x86)\"></SetDirectory>
This changed the value of ProgramFilesFolder that was being set to C:\Users\XXX\AppData\Local..... to C:\Program Files (x86) for per machine installation.
Also the above line of code does not make any difference to per user installation and installation happens at that user folder only (as desired.)
Please follow the link below
http://wixtoolset.org/documentation/manual/v3/wixui/dialog_reference/wixui_advanced.html
For a per-machine installation, the default installation location will be
[ProgramFilesFolder][ApplicationFolderName]
and the user will be able to change it in the setup UI.
For a per-user installation, the default installation location will be
[LocalAppDataFolder]Apps[ApplicationFolderName]
and the user will not be able to change it in the setup UI.
you can set the per user to 0 to enforce installation per machine - or in Program files
<WixVariable Id="WixUISupportPerUser" Value="0" />
For per-machine installation you will need admin privileges, if the user will not have admin privileges, he only has access to his local app data folder, hence that location cannot be changed.

How can I inject my custom UI in the built-in InstallDir UI?

What I'm trying to do is exactly what is described here under Inserting a custom dialog into a built-in dialog set:
http://wixtoolset.org/documentation/manual/v3/wixui/wixui_customizations.html
The documentation linked above says I should copy everything in between and including the <Fragment> from WixUI_InstallDir.wxs into my own source file. I can then adjust the Publish statements and insert my own UI.
When I try that though, I get the following:
error LGHT0091: Duplicate symbol 'WixUI:WixUI_InstallDir' found. This
typically means that an Id is duplicated. Check to make sure all your
identifiers of a given type (File, Component, Feature) are unique.
I guess that's because I have the following in my Product.wxs:
<UIRef Id="WixUI_InstallDir" />
But if I remove that, how am I supposed to reference the InstallDir UI? Because when I remove it, it compiles, but the InstallDir UI doesn't show up anymore.
I'm sure I'm doing something completely wrong but this is my first time messing with WiX, so take it easy on me :)
For reference, this is my full Product.wxs:
The ... is where the exact copy (from <Fragment> until </Fragment>) of WixUI_InstallDir.wxs resides, I left it out to prevent this post from getting too long.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'
xmlns:util='http://schemas.microsoft.com/wix/UtilExtension'
xmlns:sql='http://schemas.microsoft.com/wix/SqlExtension'>
<Product Id="*" Name="product" Language="1033" Version="1.0.0.0" Manufacturer="man" UpgradeCode="GUID">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="Shell.MACAM" Level="1">
<ComponentRef Id="SqlComponent" />
</Feature>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER"/>
<UIRef Id="WixUI_InstallDir" />
<util:User Id='SQLUser' Name='[SQLUSER]' Password='[SQLPASSWORD]' />
<UI>
<Dialog Id="AskUserForSQLServer" Width="370" Height="270">
<Control Type="Text" Id="SQLServerNameLabel" Width="50" Height="15" X="4" Y="8">
<Text>SQL Server:</Text>
</Control>
<Control Type="Edit" Id="SQLServerName" Width="181" Height="15" X="60" Y="4">
</Control>
</Dialog>
</UI>
<UIRef Id="WixUI_Minimal" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INETPUB" Name="Inetpub">
<Directory Id="INSTALLFOLDER" Name="Shell.MACAM">
<Component Id='SqlComponent' Guid='GUID'>
<CreateFolder/>
<sql:SqlDatabase Id='SqlDatabase' Database='[SQLDATABASE]' User='SQLUser' Server='[SQLSERVER]'
CreateOnInstall='yes' DropOnUninstall='yes' ContinueOnError='yes'>
</sql:SqlDatabase>
</Component>
</Directory>
</Directory>
</Directory>
</Fragment>
...
</Wix>
"Inserting" dialogs works by adding rows to the ControlEvent table in the MSI. This table has an Order column which can be used to get your NewDialog control event to run with a higher priority then the existing event.
I run an open source project called IsWiX that has project templates to accelerate setup development. One of the features of this template is what you are trying to do here. The UI-CustomDialog.wxs fragment defines a custom dialog and inserts the rows to place it in the loop. The UI.wxs fragment references the WixUI_FeatureTree dialog set and has a commented out reference to the UI-CustomDialog fragment. Uncomment and the dialog becomes active.
The different dialog sets have different dialogs so the before and after dialog names have to be tweaked when referencing different sets.
<!-- Insert into dialog sequencing by inserting control events on previous and next dialogs-->
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="CustomDlg">1</Publish>
<Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="CustomDlg" Order="3">NOT Installed</Publish>
http://iswix.codeplex.com/SourceControl/latest#main/Source/Application/IsWiXAddIn/SetupProjectTemplate/UI.wxs
http://iswix.codeplex.com/SourceControl/latest#main/Source/Application/IsWiXAddIn/SetupProjectTemplate/UI-CustomDialog.wxs
You need to change the dialog "Id" (and filename?) to something different so that you don't get Id conflicts. Then you can include/reference your personal copy of the modified dialog.

Changing the TARGETDIR in WiX

I am having problems setting the TARGETDIR path. I used dark.exe to reverse engineer a working MSI file and read any posts I could find on this subject, but I seem to be unable to set the TARGETDIR to point to the path ProgramFiles\Manufacturer\Product. Below is a distilation of my WXS file which results in my application being installed to the root of my D-drive for some reason:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="FBL - Some App"
Language="1033"
Version="1.0.0.0"
Manufacturer="Foo & Bar Limited"
UpgradeCode="780286c6-e064-4402-80d8-dd2c68b56c04">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Comments="Performs some operation that is important" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="App.1.0.0.cab" EmbedCab="yes" />
<CustomAction Id="setTARGETDIR"
Property="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Execute="firstSequence"
Return="check" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="C__App.exe"
Guid="{074586E9-A675-2734-A4CD-1CE520922A41}">
<File Id="F__App.exe"
Name="App.exe"
KeyPath="yes"
Assembly=".net"
AssemblyManifest="F__App.exe"
AssemblyApplication="F__App.exe"
DiskId="1"
Source="D:\SomePath\bin\Debug\App.exe" />
</Component>
</Directory>
<Feature Id="DefaultFeature" ConfigurableDirectory="TARGETDIR" Level="1">
<ComponentRef Id="C__App.exe" Primary="yes" />
</Feature>
<Icon Id="favicon.ico" SourceFile="d:\SomePath\favicon.ico" />
<Property Id="ARPPRODUCTICON" Value="favicon.ico" />
<UI />
<InstallExecuteSequence>
<Custom Action="setTARGETDIR" Before="CostFinalize" />
</InstallExecuteSequence>
</Product>
</Wix>
I'm sure I am missing something simple, but I cannot find any further information on what to do from here.
The following modifications were needed:
<CustomAction Id="SetTARGETDIR"
Directory="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Return="check" />
and
<InstallExecuteSequence>
<Custom Action="SetTARGETDIR" After="InstallValidate" />
</InstallExecuteSequence>
Explanation: Use the Directory attribute instead of a property (it's a type 35 custom action) and schedule this action after InstallValidate in the execute sequence - that's when directories are checked for write access and truly set.
(Thanks to Narina Chandra Sekhar, from the WiX user group for the answer on this.)
This is strange...I had the same issue but your answer didn't work for me. All I needed was this:
<Product>
<SetProperty Id='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\' Before='FindRelatedProducts' />
...
</Product>
But then again I think something else in my installer may have been setting the TARGETDIR directory from the property; I was working with some legacy stuff.
Edit: Actually, that was a bad idea. A lot of times, some of these custom actions that are built in can be called at different parts of the installation process, so its just better to add a custom action to set the property.
Here is what worked for me:
<Product>
<CustomAction Id='SetTARGETDIR' Property='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\'/>
...
</Product>
<InstallUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</InstallUISequence>
<AdminUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</AdminUISequence>
Nothing worked for me so what I did is to run the msi with a command line setting the property of the installation directory. By default my program would be installed to drive C but sometimes I wanted it to be installed to D drive so here is what I did:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="XServer">
</Directory>
</Directory>
</Directory>
Here is the command line:
XServer.msi /L*v log.log APPLICATIONROOTDIRECTORY="D:\Program Files (x86)\XServer"
This actually worked for me. The CostFinalize action is where TARGETDIR Directory is defined.
<SetProperty Id="TARGETDIR" Value="[ROOTDRIVE]MyCompany" Sequence="first" Before="CostFinalize">NOT Installed AND NOT TARGETDIR</SetProperty>
I tried changing the installation dir via custom action (cause I needed code to figure out the path with code - long story), and what solved it for me what the timing - I had to schedule the custom action to:
After="CostInitialize"