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.
Related
I've followed the official Major Upgrade guide and I seem to be missing something.
Here is my MCVE:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="PUT-GUID-HERE" Version="31.00.0000">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla 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="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="tenlira.ini" Guid="*">
<File Id="tenlira.ini" Source="..\ConfigurationFile\x64\tenlira.ini" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<ComponentRef Id="tenlira.ini" />
</Feature>
</Product>
</Wix>
All it does is simply installing a single file as an example. So far, so good. Now, all I do is add another Component and File and off course the corresponding ComponentRef in Feature. I specifically leave the Version as is: 31.00.0000. What I expected is that the new installer will not perform a Major Upgrade, but it does. Why? Also, there is now 2 entries in Add/Remove Programs.
Please help me find out what am I missing here. Thanks. Refael.
UPDATE:
Posting the question got me to reread the documentation again and I discovered that the AllowSameVersionUpgrades thingy in the MajorUpgrade element should be set to yes. This time there is only one entree in the Add/Remove Programs, but it still performs Major Upgrade. Why?
UPDATE: Here is a list to help debug failing major upgrades by identifying the most common problems: Common causes of failed major upgrades
Major Upgrade - "The Old, Manual Way"
I guess you are hitting an oddity that may not be handled entirely as expected by the WiX MajorUpgrade element by combining the auto-generated product GUID, the AllowSameVersionUpgrades set to yes and keeping the version number the same.
I can't see any obvious way to set the MinInclusive attribute in WiX's MajorUpgrade element - I could be mistaken, there might be a way I am unaware of. For what it is worth, I am not too keen on allowing "same version upgrades".
However, you could try to "use the old way" to author the Upgrade table using the "older elements" Upgrade and UpgradeVersion. The MajorUpgrade element is essentially a "convenience" feature to set up your major upgrades easily, and I believe it works for most users. Bob Arnson has a blog explaining the introduction of the MajorUpgrade element. This blog also shows a sample of how to do things "manually" with the "older elements" Upgrade and UpgradeVersion (do check it out).
I made a quick mock-up that might do what you want, it is just a "rough draft" - can't make any guarantees. I use preprocessor defines to set some variables that can be referenced in the WiX source file - as a C++ developer this is a piece of cake for you so I won't waste time explaining it - the source should make sense:
<?define MyProductVersion = "31.00.0000" ?>
<?define MyProductCode = "PUT-GUID-HERE" ?>
<?define MyUpgradeCode = "PUT-GUID-HERE" ?>
<!--Recommendation: set a path variable that you can redirect at will to a new release folder (new build output folder): -->
<!-- <?define MyBasePath = "C:\Projects\MyApp\Release\31.00.0000\" ?> -->
<!-- SAMPLE:
<Component Win64="yes" Feature="MainApplication">
<File Source="$(var.MyBasePath)\myapp.exe" />
</Component> -->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="$(var.MyProductCode)" Codepage="1252" Language="1033" Manufacturer="Bla Corporation"
Name="Bla" UpgradeCode="$(var.MyUpgradeCode)" Version="$(var.MyProductVersion)">
<Package Comments="Contact: Refael Sheinker, refael.sheinker#bla.com." Description="Bla"
InstallerVersion="500"
Compressed="yes"
InstallScope="perMachine"
Keywords="Installer,MSI,Database" Languages="1033" Manufacturer="Bla Corporation" Platform="x64" />
<Media Id="1" Cabinet="my_application.cab" EmbedCab="yes" />
<!-- Major upgrade -->
<Upgrade Id="$(var.MyUpgradeCode)">
<!-- Downgrade Protection -->
<UpgradeVersion Minimum="$(var.MyProductVersion)" OnlyDetect="yes" IncludeMinimum="yes" Property="DOWNGRADE_DETECTED" />
<!-- Major Upgrade Configuration -->
<UpgradeVersion IncludeMinimum="no" Maximum="$(var.MyProductVersion)" IncludeMaximum="no" MigrateFeatures="yes" Property="UPGRADE_DETECTED" />
</Upgrade>
<!-- Major Upgrade: Schedule RemoveExistingProducts -->
<InstallExecuteSequence>
<!-- Potential scheduling (after): InstallValidate, InstallInitialize, InstallExecute, InstallExecuteAgain, InstallFinalize -->
<RemoveExistingProducts After="InstallInitialize" />
</InstallExecuteSequence>
<!--Launch Condition: Abort setup if higher version found-->
<Condition Message="!(loc.NewerVersionDetected)">
NOT DOWNGRADE_DETECTED
</Condition>
<Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONROOTDIRECTORY" />
<UIRef Id="WixUI_InstallDir" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="PROGRAMFILESSUBDIR" Name="Bla">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="BlaInternal" />
</Directory>
</Directory>
</Directory>
<DirectoryRef Id="APPLICATIONROOTDIRECTORY">
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
</DirectoryRef>
<Feature Id="MainApplication" Title="TenLira" Level="1">
<!--<ComponentRef Id="tenlira.ini" />-->
</Feature>
</Product>
</Wix>
Now the !(loc.NewerVersionDetected) has to be explained. This is a localized string (for delivering your setup in different languages). To use it, right click your WiX project in Visual Studio and go: Add New Item... => Localization File => Add. As the localization file is added, your output MSI will also now go into a en-us folder under your main output location (Debug or Release).
In the localization file, add:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="NewerVersionDetected">A later version of [ProductName] is already installed.</String>
</WixLocalization>
And you should now be able to add new strings to this file and easily translate your whole setup using such language files.
Also add the WiX GUI extension. Right click "References". Add Reference... => Browse to WixUIExtension.dll => Double click this file, and press OK. Normal folder to find the file is: C:\Program Files (x86)\WiX Toolset v3.11\bin.
INI-Files
I just want to mention that INI files should ideally be installed via the IniFile table (entries are treated as atomic key-value pairs allowing advanced merging of keys and values for existing INI files), and not via the File table (the file is treated as a regular file either overwriting the whole existing file or leaving it in place - not enforcing any new values). The WiX element corresponding to the MSI IniFile table is naturally the IniFile element.
An ad-hoc sample:
<Component Id="Test.ini" Guid="PUT-GUID-HERE" Win64="yes" Feature="MainApplication">
<CreateFolder Directory="APPLICATIONROOTDIRECTORY" />
<IniFile Id="SomeSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting1" Name="Test.ini" Section="MySection" Value="Some Setting" />
<IniFile Id="OtherSetting" Action="addLine" Directory="APPLICATIONROOTDIRECTORY" Key="Setting2" Name="Test.ini" Section="MySection" Value="Other Setting" />
</Component>
Links:
Adding entries to MSI UpgradeTable to remove related products
It does a major upgrade because both MSIs have the same UpgradeCode and you have now specified AllowSameVersionUpgrades, so it does the upgrade where it didn't before.
Your build generates a new ProductCode every time, so each MSI is a new product, so you will get it installed twice if it doesn't do an upgrade and once if it does. You may have some assumption about the way upgrades work that you haven't spelled out.
I had the same problem where Version is same, but the Id is different creating multiple entries in Add/Remove programs.
My simple fix was to set AllowSameVersionUpgrades="yes".
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of $(var.ServiceName) is already installed." />
my idea is make an uninstall file with .msi install file. I read some information about creating uninstaller shortcut here: http://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/create_uninstall_shortcut.html , But i cant found information about make uninstall file after msi build , maybe whom know it's possible ? and if possible how i can do it ? or maybe it possible to do with cmd script? Just write script for automatically uninstall my program from mashine. My code is :
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"><?define WpfApp1_TargetDir=$(var.WpfApp1.TargetDir)?>
<Product Id="*" Name="SetupProject2" Language="1033" Version="1.0.0.0" Manufacturer="Andrejka" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<Property Id="WIXUI_INSTALLDIR" Value="TESTFILEPRODUCTDIR" />
<Property Id="WixShellExecTarget" Value="[#WpfApp1.exe]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<Property Id="LAUNCH_APP_ON_EXIT" Value="1" />
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFiles'/>
</InstallExecuteSequence>
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes"/>
<Feature Id="ProductFeature" Title="SetupProject2" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="TESTFILEPRODUCTDIR" Name="SetupProject2">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="SetupProject2" />
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<!-- TODO: Remove the comments around this Component element and the ComponentRef below in order to add resources to this installer. -->
<!-- <Component Id="ProductComponent"> -->
<!-- TODO: Insert files, registry keys, and other resources here. -->
<!-- </Component> -->
<Component Id="WpfApp1.exe" Guid="*">
<File Id="WpfApp1.exe" Name="WpfApp1.exe" Source="$(var.WpfApp1_TargetDir)WpfApp1.exe" />
</Component>
<Component Id="WpfApp1.exe.config" Guid="*">
<File Id="WpfApp1.exe.config" Name="WpfApp1.exe.config" Source="$(var.WpfApp1_TargetDir)WpfApp1.exe.config" />
</Component>
<Component Id="aws_sdk_net_core_support.dll" Guid="*">
<File Id="aws_sdk_net_core_support.dll" Name="aws-sdk-net-core-support.dll" Source="$(var.WpfApp1_TargetDir)aws-sdk-net-core-support.dll" />
</Component>
<Component Id="AWSSDK.Core.dll" Guid="*">
<File Id="AWSSDK.Core.dll" Name="AWSSDK.Core.dll" Source="$(var.WpfApp1_TargetDir)AWSSDK.Core.dll" />
</Component>
<Component Id="AWSSDK.SimpleNotificationService.dll" Guid="*">
<File Id="AWSSDK.SimpleNotificationService.dll" Name="AWSSDK.SimpleNotificationService.dll" Source="$(var.WpfApp1_TargetDir)AWSSDK.SimpleNotificationService.dll" />
</Component>
<Component Id="MimeSharp.dll" Guid="*">
<File Id="MimeSharp.dll" Name="MimeSharp.dll" Source="$(var.WpfApp1_TargetDir)MimeSharp.dll" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
In general you are not supposed to put uninstall shortcuts in the start menu, it is in fact a violation of Microsoft's logo requirements for Windows applications I believe. Rather you should let people uninstall your product the normal way via the add/remove programs applet.
UPDATE: I found this answer with some more information on this topic: Shortcuts with name "Uninstall <Program Name>" are not displayed in Windows 8/8.1/10
Also, just so it is clear, uninstall, is a built-in feature of MSI files - it is always automatically available unless actively blocked (such as some applications hiding themselves from display in add/remove programs). There is nothing extra you have to do in your WiX sources to support uninstall properly. Just follow Windows Installer guidelines and it comes "for free".
If what you are asking is for a way to create an uninstall batch file, then you can find a plethora of ways to uninstall your MSI file in this "uninstall reference": Uninstalling an MSI file from the command line without using msiexec.
In short, just run the command line below to uninstall your MSI if you have the MSI's product code (you can find your product code by querying your system as described here: How can I find the product GUID of an installed MSI setup? - you might need to look it up since you auto-generate your product code):
msiexec.exe /x {your-product-guid}
or just uninstall by referring to your original MSI installation file like this:
msiexec.exe /x "c:\filename.msi
See the linked answer above (the uninstall reference) for a lot more information about this.
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.
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>
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"