I am having a problem very similar to the one described here: ProgramFiles64Folder is installing to \Program Files (x86)\ in WIX Installer
However, the solution there does not work for me. Wix still generates a .msi that installs to C:\Program Files (x86)
I placed the following code in my Product.wxs file:
<?if $(var.Platform) = x64 ?>
<?define Win64 = "yes" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?define ConfigFolder = "Release" ?>
<?else ?>
<?define Win64 = "no" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?define ConfigFolder = "Release_x86" ?>
<?endif?>
Then later I try to specify installation folder as follows:
<Directory Name="SourceDir" Id="TARGETDIR">
<Directory Name="$(var.PlatformProgramFilesFolder)" Id="$(var.PlatformProgramFilesFolder)">
...
I verified that var.Platform is set properly because it copies source files from the correct ConfigFolder. However, it seems that both ProgramFiles64Folder and ProgramFilesFolder are set to C:\Program Files (x86)
I verified that candle.exe is invoked with -dPlatform=x64 option.
I even tried to specify platform in my Package tag
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Platform="x64" />
Nothing helps, it still tries to install to C:\Program Files (x86)
Any idea what else I can try?
Thank you.
I am using WiX version 3.9
It turned out that a different .wxs file was messing with WixPerUserFolder and other related variables.
The following code fix the problem:
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder" Property="WixPerMachineFolder"
Value="[ProgramFiles64Folder][ApplicationFolderName]" Execute="immediate" />
<InstallUISequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallExecuteSequence>
BTW, I created a project to simplify the configuration of wix. Hope it can help: https://github.com/xinnj/WiXCover
The only thing I can think of is that the components you are installing to that location are 32-bit components, so they get redirected to the x86 location. A 64-bit package can have 32 and 64-bit components, so you may need to mark them explicitly as Win64='yes'
Follow the sample in this blog and release a new 64 bit package and you will have your installation in Program Files folder.
http://msdn.microsoft.com/en-us/library/gg513929.aspx
Using WixUI_Advanced? This doesn't set the correct default folder on x64.
Workaround is to add this to the Product item:
<!-- Workaround Wix Bug: https://github.com/wixtoolset/issues/issues/2165 -->
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder" Property="WixPerMachineFolder"
Value="[$(var.PlatformProgramFilesFolder)][ApplicationFolderName]" Execute="immediate" />
<InstallUISequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallExecuteSequence>
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize" />
For the bug description and the workaround source look here:
https://github.com/wixtoolset/issues/issues/2165
Related
How can i use Wix to check a registry setting, and depending on that value, select the correct MSI from 2 MSIs to install? The registry entry denotes x86 or x64. If x64, the Wix installer should then installed the 64 bit Msi. If x86, it should install 32 bit version.
I tried this, but I just get an error on install that says
"This installation package could not be opened. Contact the vendor to verify that this is a valid Windows Installer package."
Both "chained" MSIs function correctly by themselves.
This is a file Bundle.wxs and is the only file in the Wix project.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="SingleInstaller" Version="1.0.0.0" Manufacturer="Microsoft" UpgradeCode="935daa4e-9b25-4fef-a4a1-0cf6af71a939">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"/>
<!--Search the registry entries for each because it may be under Wow6432-->
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\SomeEntry\" Value="Bitness" Variable="MyRegEntry" Win64="no" />
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\SomeEntry\" Value="Bitness" Variable="MyRegEntry" Win64="yes" />
<Chain>
<!-- TODO: Define the list of chained packages. -->
<!--<MsiPackage SourceFile="D:\Dev\Cwds_Install\bin\x86\Release\JMPS-CC-CWDS3.0.0.0.msi" InstallCondition="Jmps32Bit = x86" Id="Cwds32"/>-->
<MsiPackage SourceFile="D:MyProgram.msi" InstallCondition="MyRegEntry = x86" Id="MyProgram32" />
<MsiPackage SourceFile="D:MyProgram.msi" InstallCondition="MyRegEntry = x64" Id="MyProgram64" />
</Chain>
</Bundle>
</Wix>
I wrote Wix Setup program, that wraps PyTangoArchiving-7.3.2.win-amd64.exe file into into PyTangoArchivingInstaller.msi package.
The installation procces is correct I think, in control pannel -> Programs I can see two additional programs installed:
PyTangoArchiving-7.3.2.win-amd64.exe - the program I wanted to install and
my wrapper - PyTangoArchivingInstaller.
But when I try to uninstall the application, only wrapper is being uninstalled and whole program (PyTangoArchiving-7.3.2.win-amd64.exe ) is still there, I have to uninstall it manually from Control Panel.
Can sb help me with this?
Here is my code:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="PyTangoArchivingInstaller" Language="1033" Version="1.0.0.0" Manufacturer="test" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<WixVariable Id="WixUILicenseRtf" Value="$(var.ProjectDir)\License.rtf"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes"/>
<UIRef Id="WixUI_InstallDir"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id='TempFolder'>
<Directory Id="INSTALLLOCATION" Name="MyApp" >
<Component Id='MyComponent' Guid='*'>
<File Id="mysetup_exe" Source="PyTangoArchiving-7.3.2.win-amd64.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentRef Id="MyComponent" />
</Feature>
<CustomAction Id="run_setup" FileKey="mysetup_exe" ExeCommand="/SP- /SILENT /SUPPRESSMSGBOXES /LANG=English
/NOCANCEL /DIR="[INSTALLLOCATION]""
Execute="deferred" Impersonate="no"
Return="check" />
<InstallExecuteSequence>
<Custom Action="run_setup" Sequence='5401'>NOT Installed</Custom>
</InstallExecuteSequence>
</Product>
</Wix>
As a general comment, you shouldn't usually be running another exe from inside your MSI, especially if it is an install that shows up in add/remove programs. You should instead use a bootstrapper to chain together multiple installs and this is the preferred way to do what you are trying to do.
Since you run your setup_exe from a custom action, you also need a corresponding custom action to uninstall it.
It would basically be the same format as the one you use to install except with the uninstall command line arguments, whatever they may be.
You will need to schedule your uninstall custom action before the "RemoveFiles" standard action so that the setup exe still exists when you try to run the custom action. You should also condition this custom action with REMOVE~="ALL" AND NOT UPGRADINGPRODUCTCODE.
This approach will run into problems when you try to support upgrades with/without upgrades to the packaged exe install. It is highly suggested you use either the wix burn bootstrapper (bit of a learning curve) or one of the other available bootstrappers for multiple install installations. These would more robustly and correctly support two installs along with upgrades and uninstalls.
I'm using Wix 3.11 and trying to set the install privileges of my package conditionally.
What I'm trying to do is:
<?if Privileged = 0 ?>
<Package InstallerVersion="405" Compressed="yes" InstallScope="perUser" InstallPrivileges="limited" />
<?else ?>
<Package InstallerVersion="405" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" />
<?endif ?>
However this doesn't work. When installing, the one with elevated privileges is always picked.
Also, I've tried to create a variable in a .wxi file and set it like this:
.wxi file:
<?if Privileged = 0 ?>
<?define myScope = "perUser" ?>
<?define myPrivileges = "limited" ?>
<?else?>
<?define myScope = "perMachine" ?>
<?define myPrivileges = "elevated" ?>
<?endif?>
.wxs file:
<Package InstallerVersion="405" Compressed="yes" InstallScope="$(var.myScope)" InstallPrivileges="$(var.myPrivileges)" />
But the same happens again: elevated privileges are always picked.
I did my tests on 2 different machines, with non-admin users.
I did not find any solution on the internet so I'm wondering: is it possible to set up a package conditionally?
Thanks for your time.
EDIT:
I have found the AdminUser property, which seems to be exactly what I need.
I changed my wxs file accordingly to have AdminUser set:
<Package InstallerVersion="500" Compressed="yes" />
<SetProperty Id="MSIUSEREALADMINDETECTION" Value="1" Sequence="first"/>
<SetProperty Id="ALLUSERS" Value="2" Sequence="first"/>
<SetProperty Id="MSIINSTALLPERUSER" Value="1" Sequence="first"> <![CDATA[NOT AdminUser]]> </SetProperty>
When reading the log file of the installation, I noticed AdminUser was set before MSIUSEREALADMINDETECTION, and setting MSIUSEREALADMINDETECTION wouldn't trigger a reset for AdminUser.
I scheduled my SetProperties to the most prior action I could find, which was "FindRelatedProducts", however AdminUser is set even before that (actually before both installExecuteSequence and installUISequence), I was unable to get MSIUSEREALADMINDETECTION set first.
I believe there is no way to determine wether you are running your installation under an admin or a standard session.
If anyone know a solution, please feel free to advise.
Thank you Michael and Brian for your time.
I added a custom action that should kill my application using taskkill CMD when someone tries to uninstall it using the add/remove in the control panel using the following code :
<Property Id="TASKKILL">
<DirectorySearch Id="SysDir" Path="[SystemFolder]" Depth="1">
<FileSearch Id="taskkillExe" Name="taskkill.exe" />
</DirectorySearch>
</Property>
<CustomAction Id="ServerKill" Property="TASKKILL" Execute="immediate" Impersonate="yes" Return="ignore" ExeCommand="/F /FI "IMAGENAME EQ App.exe""/>
<InstallExecuteSequence>
<Custom Action="ServerKill" After="FindRelatedProducts"/>
</InstallExecuteSequence>
However this does not work. If someone can tell me how to fix it or even share a better/easier way to kill my app process I would be grateful.
p.s
also tried to use WMIC using cmd. That really didn't work and the installation itself did not finish at all because of this.
Perhaps you can try the CloseApplication feature from the Util schema:
http://wixtoolset.org/documentation/manual/v3/xsd/util/closeapplication.html
See here for an example code snippet: https://sourceforge.net/p/wix/mailman/message/20186650/
UPDATE: I ran some tests and this element works a little differently from what I expected. The first thing you need to add is the reference to the wixUtilExtension file. On the command line this is:
candle -ext WiXUtilExtension Test.wxs
light -ext WixUtilExtension Test.wixobj
In Visual Studio I think you simply add a project reference to WixUtilExtension.dll.
Then you simply add something like this to your wxs source file:
<util:CloseApplication Id="CloseNotepad" Target="notepad.exe"
CloseMessage="yes" RebootPrompt="no">
</util:CloseApplication>
And add this at the top of your wxs file:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
It looks like Wix takes care of the rest (custom actions and a custom table in your MSI with the list of processes to kill).
Here is my full test file:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" UpgradeCode="12345678-1234-1234-1234-111111111111"
Name="Example Product Name" Version="0.0.1" Manufacturer="Example Company Name" Language="1033">
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package"/>
<Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="ApplicationFiles" Guid="*">
</Component>
</Directory>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="ApplicationFiles"/>
</Feature>
<util:CloseApplication Id="CloseNotepad" Target="notepad.exe" CloseMessage="yes" RebootPrompt="no"></util:CloseApplication>
</Product>
</Wix>
Links: Some related or marginally related links for easy retrieval.
Windows Installer-Avoid FileinUse dialog box when Installing a package
Reboot on install, Don't reboot on uninstall
How to kill a process upon uninstall using WiX
Wix's util:CloseApplication extension doesn't seem to work
Alternatively a simple VBScript scheduled to run on uninstall should do the job:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'Notepad.exe'")
For Each objProcess in colProcessList
objProcess.Terminate()
Next
I have a problem with passing the required variable. the problem is this:
I am creating and installer that needs to work on both x86 and x64. changing the installation destination I manage with the following code:
<?if $(sys.BUILDARCH)=x64?>
<?define PlatformProgramFilesFolder = "ProgramFilesX86"?>
<?define FOLDER_NAME = Program Files (x86) ?>
<?else?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder"?>
<?define FOLDER_NAME = Program Files ?>
<?endif?>
<Directory Id="$(var.PlatformProgramFilesFolder)" Name="$(var.FOLDER_NAME)">
this works fine, however I also have an CA.dll that needs to get the variable FOLDER_NAME since the script makes some changes in files and the path to those files need to be changed as well in order to point towards the right location.
I do have a custom action that transfers propertys to the same script
<Property Id ="MACHINE_ID_NUMBER" Secure ="yes">
<![CDATA[]]>
</Property>
<Property Id ="MACHINE_TYPE" Secure ="yes">
<![CDATA[]]>
</Property>
<CustomAction
Id="SetProperties"
Property="ValueAdaptionScript"
HideTarget="no"
Value="MachineID=[MACHINE_ID_NUMBER];MachineType=[MACHINE_TYPE]"
/>
<CustomAction
Id="ValueAdaptionScript"
BinaryKey="StringTransfer"
DllEntry="CustomAction1"
Execute="deferred"
Impersonate="no"
Return="check"
/>
<InstallExecuteSequence>
<Custom Action="SetProperties" Before="ValueAdaptionScript" />
<Custom Action="ValueAdaptionScript" Before="InstallFinalize">NOT REMOVE="ALL"</Custom>
</InstallExecuteSequence>
The problem is that I am not able to get those two pieces of code combined and working. the problem is that I can't get the value of the variable in an property as is recuired to use it in the custom action.
what am I missing to get it working or am I doing it completely the wrong way?
thanks in advance,
I figured it out myself, it turned out to be pretty easy I was just looking in the wrong direction.
this is what I did:
<Property Id ="PLATFORM_PROGRAM_FILES" Secure ="yes">
<![CDATA[$(var.FOLDER_NAME)]]>
</Property>
all I had to do was to give the property the variable.