Check condition and continue installation using Wix Toolset - wix

I have a .wxs file for program installation. I want to pass a part of installation depending on the OS version (for ex. execute if OS verion > XP and pass if <= XP) and continue to install other parts. It means that i've already installed some components, and during the installation want to check (according to the current OS), should i install next component or not. If yes - install, if not - installation of the component should be skipped. Of course, after that full installation should continue. I don't want to abort the installation and remove installed components, just skip one component. How can i do it?
Also, I found this one link. There is a block install case, but i want to continue installation after condition.
There is another assumption - we can use
<?if *condition* ?> ... <?endif?>
blocks, but i really don't understand how to get OS info there.
Any ideas?

You don't want to use <?if ... ?> these are preprocessor directives like #ifdef and #ifndef in c++ and just determine whether or not the part between the if is included for compilation or not. This will only be evaluated at built time on the build machine.
Something like this would stop your installation from running on Windows XP or earlier machines.
<Condition Message="!(loc.OSNotSupported)">Installed OR VersionNT > 501 OR VersionNT64 > 501</Condition>
Similar conditions can be used to dictate whether or not a component is installed, a feature is installed, or a custom action is run.
If you update your question and leave a comment on this answer I will try to update my answer to better answer you question.
To install certain components dependent on the OS of the machine you are running is quite simple, just add the following to your <component>
<Component Id="InstallMeOnXP" Guid="*">
<Condition>VersionNT <= 501 OR VersionNT64 <= 501</Condition>
<File Id="XPOnly.dll" KeyPath="yes" Source="$(var.BinariesDir)\_bin\XPOnly.dll" />
</Component>
If the condition evaluates to TRUE then the component will be installed, otherwise it will not be installed. More info on the Condition element in wix.
Here is the information about the default VersionNT and VersionNT64 properties for the Windows Installer.

Related

Overriding feature on command line when installing over the top of previous install

I have an installer and I have a feature that I can turn on or off if I pass on the msiexec.exe commandline a property named FEATUREX to be 0 or 1. If the value is zero, the feature is not installed. If the value is 1, then the feature is installed. It's a COM component. Part of the install always installs the COM component so that it can be enabled later by changing some registry values in the system. The part of installing the COM component is not FEATUREX since the COM component is always installed. Enabling the COM component to the system is FEATUREX and it adds a CLSID to a subkey in Windows and the system starts using the COM component.
If the software is not installed or has been uninstalled, then my logic works. The problem occurs when I want to install over the top of a previous installation. I do not want to require that the previous installation be uninstalled. I just want to install over the top, and if a sysadmin installs over the top and enables or disables FEATUREX, then FEATUREX should be installed or not installed depending on the value of FEATUREX on the command line.
Usually customers might want to install with FEATUREX disabled, then enable FEATUREX (independent of the installer), but setting the registry key.
However, when installing over the top, the system ignores FEATUREX property on the command line and the real Feature X is enabled or disabled depending on whether it was originally enabled or disabled.
I tried changing the GUID of the Component, and that didn't work...IDK...I was just guessing.
If I change the Feature ID from ActivateFeatureX to ActivateFeatureX2 then the command line property FEATUREX works...but then, if the property is not passed on the command line, Feature X is not installed if it was previously installed.
I was wondering what the solution might be? I have thoughts of a simple checkbox tied to a registry DWORD value such that the COM component would fail to be created if the DWORD value is 0... but IDK.
<Feature Id='ActivateFeatureX' Title='Feature X' Description='If this dropdown is changed from the red "X" to the grey disk icon, then Feature X will be enabled'
Level='2' AllowAdvertise='no' InstallDefault="local" Display="3">
<Condition Level="1">FEATUREX=1</Condition>
<Condition Level="0">FEATUREX=0</Condition>
<ComponentRef Id='ActivateFeatureX' />
</Feature>
<Component Id="ActivateFeatureX" Location="local" Guid="4c0d547f-d9ae-4c5f-bd21-d8360c00dd46">
<RegistryValue Root='HKLM' Key='SOFTWARE\Microsoft\Windows\CurrentVersion\SOMEWHERE\SOMEHOW\{$(var.FeatureXRegistryGUID)}' Type='string' Value='$(var.TheProject.TargetName)' KeyPath='yes' />
</Component>
Instead of trying to use a Condition to control the state of ActivateFeatureX (which has limitations during repair and upgrade), consider using the ADDLOCAL and REMOVE properties to change the state of the Feature directly.

Wix toolset Bundle Chain installation global condition

CONTEXT: I created a Bootstrapper installer in order to install, if needed, the .net framework 4.8. together with the setup program I want to deliver with it.
Up to here all works nice: my program gets installed always and the .net just if needed.
The thing is that I need to add some more checks to this installer, for example check for a registry key (if another program proper version is installed) and if this does not meet the condition, then the complete installation should be aborted, nothing should be installed.
PROBLEM: the InstallCondition I have added affects just the MsiPackage but the rest of the installation seems to be considered as totally fine and installation finishes successfully, here the interesting part of code:
<util:RegistrySearch Id="OtherProgramVersionId" Root="HKLM" Key="SOFTWARE\XXX\Install::Version" Variable="OtherProgramVersion"/>
<Chain>
<PackageGroupRef Id="NetFx48Redist" />
<MsiPackage
Id="MySuperProgram.Setup"
SourceFile="$(var.MySuperProgram.Setup.TargetPath)"
InstallCondition="OtherProgramVersion >= v10.0"/>
</Chain>
As said before, even the registry key is not found or it does not fulfill the condition, the installation seems to continue "successfully" and I get it in the ControlPanel->Programs as installed... but the main .msi was not really installed! (checking the destination folder, it's empty)
QUESTION: How can I add a global condition in order to stop completely any installation at all and show the user a message with the condition not fulfilled? If possible with a standard dialog.
I have seen (and I am still experiencing) with conditions, but seems they affect just one of the items in the chain... or they seem to break the installation somehow, I have tried adding to the .msi setup creation, file Product.wxs, the condition in order to abort this installation, but when installing I get this not passed condition as a setup error, seems the exit is not clean at all... even able to see the log where I see something like this:
Error 0x80070643: Failed to install MSI package.
Thanks in advance!
If you're using WixStandardBootstrapperApplication, you can use bal:Condition to define bundle-level conditions. The WiX documentation has a sample: https://wixtoolset.org/documentation/manual/v3/howtos/redistributables_and_install_checks/block_stdba_install_on_reg.html

Setting conditions on Components in Wix

In my Wix, I have lots of files included in this way:
<Component Id="mycomponent" Guid="*" Feature="Core" >
<Condition>$(var.Include) = 1</Condition>
<File Id="mycomponent.file" KeyPath="yes"
Source="$(var.BinDir)\mycomponent.file" />
</Component>
So I can pass in a different value of var.Include to generate packages for different environment.
While the resulting packages do seem to work, however I noticed the size of the packages are always quite big even when I set it to not include these components. It looks as if WiX is always including all components in building the msi, and only chose to not install these components when the package was build with var.Include = 0...
Is this a normal behavior?
The condition element is used to determine whether a component gets installed not whether it gets included in the build or not. Also be sure not to confuse Windows Installer properties used in Conditional Statements and preprocessor variables / statements. Two different beasts.
You can confirm by opening your MSI output file using some File compressing/uncompressing software such as 7zip and open the package.cab file inside the opened MSI file. and check whether your files with the id like "mycomponent" is present there or not.
I hope it is expected since it is dependent on the variable and that can be something which even can be set from install command call as install property.
UPDATE: You can amend the WIX like below by using Preprocessor statements, so it can exclude these optional component from the resulting msi
<?if $(env.MySku) = Enterprise ?>
<Component Id="mycomponent" Guid="*" Feature="Core">
<Condition>$(var.Include) = 1</Condition>
<File Id="mycomponent.file" KeyPath="yes" Source="$(var.BinDir)\mycomponent.file" />
</Component>
<?endif ?>
As #RinoTom and #Christopher point out, install-time selection (Condition tag) is very different from build-time selection (?if meta-tag). To be selectable at install time, the included components must be in the .msi . The advantage of this approach is that you can set the properties that determine their conditions, not only at build time, but at install time as well via dialogs or AppSearch.
But what you're asking for is multiple package builds, each tailored to a specific set of conditions, selected at build time. An alternative that might work for you is to define each of the optional components as a Fragment in a separate file. Then for each package configuration, compile only the fragments you want in it:
del /q *.wixobj
candle main_package.wxs
for %%f in (optional_1.wxs optional_5.wxs optional_27.wxs) do candle %%f
light *.wixobj -out tailored_package_A.msi
Since only those fragments you wanted included have been compiled to .wixobj, only they appear in the output package. This scales particularly nicely if you have some components that are always present, but only a handful that are optional.

IzPack: is possible to create one app updater?

I created one installer with IzPack. Everything works fine. Now I'm wondering, is there a good way to create one installer that will take care of update the application if this already exists?
I tested running the installer again, but he not recognize that the application is installed.
I have used IzPack for installing and updating. IzPack does not natively tie in with any packaging system so there is no way for IzPack to conclusively know if something has been installed. You might try to interact with registry or some specific flie you create at install time but that is still messy (to me anyway).
IzPack does however check if a file already exists before overwriting it so if you are running an update then an example is that you would want binaries to be updated but user configuration left alone so do something like this inside the packs element:
<packs>
<pack name="CorePack" required="yes" preselected="yes">
<description>The core of the app.</description>
<file src="bin/binaryapp" targetdir="$INSTALL_PATH/bin"
override="true">
<os family="unix" />
</file>
<file src="etc/config.conf" targetdir="/etc/appdir">
<os family="unix" />
</file>
</pack>
</packs>
You see that the binary has override="true" where the config does not (by default override=false). Binary gets updated, config does not.
Jeff
CheckedHelloPanel will do your job, at least for windows. It writes something to the registry and checks this if you try to reinstall.

Install a file regardless of version number with WiX

MyApp version 1.0 contained the file foo.dll. The version of this file was version 10.5.567. Now MyApp is version 2.0 and the version of foo.dll is 2.0.123. The version is LOWER than the old version. The vendor who wrote this dll decided to go backwards with the file version number. This is not a decision I can change.
How do I get WiX to always install this file?
The RemoveExistingProducts action is scheduled after the InstallFinalize action and also cannot be changed.
InstallShield had an 'always overwrite' flag but I don't think I can mimic this without changing the behavior of all files via a compiler switch. I do not want this. I just want to update THIS ONE file.
I have also tried
<RemoveFile Id="foo.dll" On="install" Name="foo.dll" />
But this did not work either. I end up getting 'Error 2753 The file foo.dll is not marked for installation' later.
It is really crazy this post is 10 years old and we also have this problem. The other approaches did not work for us.
How to solve it:
All files which should be copied regardless of their version, must be in their own component
Component element must have a unique Guid, not a *
Set KeyPath to no in the inner File element
Example:
<Component Id="cmpExample" Guid="{5ABE7229-C247-4CBA-B8DE-2C4968CD103E}" >
<File Id="fileExample" KeyPath="no" Source="$(var.TargetDir)\SomeExample.dll" />
</Component>
I would recommend to aggregate all those component elements in a component group. And furthermore you can use XML Transformation to get rid of those files if you use heat.exe to harvest all your files.
With this solution you can copy the file, even if the installed file version is higher. And it still works as expected when a higher file version will be installed with your upgrade.
This isn't easy because it is against the standard behaviour of MSI-packages. When compiling, you have to set supress-file-options with -sf in light.exe. Then there are no file-informations from your files read. You can set DefaultVersion this version will be used.
I have also used RemoveFile in a solution, but i can say that it works. I have add it in same componente where i add the file.
<Component>
<File DiskId="1" Id="fooDLL" Name="foo.dll" Vital="yes"
DefaultVersion="$(var.MAJORVERSION).$(var.MINORVERSION).$(var.BUILDVERSION)"
DefaultLanguage="0"></File>
<RemoveFile Id='RemoveOldDLL' On='install' Name='foo.dll'/>
</Componente>
This is not a clean way, but to remove an old version it works for me.
I answered a similar question a while back:
Forcing an upgrade of a file that is modified during its initial installation
I think I would use a companion file to solve this problem, but you might get validation errors since the file in question is a dll and hence considered an executable. I believe it would still work, and reliably so.
Annotation
Force always overwrite in Light.exe output with the "InstallShield trick":
XPath="/wixOutput/table[#name='File']/row/field[5]" InnerText=„65535.0.0.0“
One thing that could be worth trying is to set RemoveExistingProducts real early in the sequence. The MSI should then remove the old program first, then install the upgrade. This will solve your issue. e.g.
<InstallExecuteSequence>
<RemoveExistingProducts After="CostFinalize" />
</InstallExecuteSequence>