I have a Wix Bundle that contains several packages. A couple of packages are mutually exclusive. By that I mean they are both included because one needs to be installed on 32-bit machines, the other on 64-bit machines. To solve that problem, I have defined a package group like this:
<Fragment>
<PackageGroup Id="Drivers">
<MsiPackage Id="Driversx64" InstallCondition="VersionNT64" SourceFile="SRC\drivers64.msi" DisplayInternalUI="no" Visible="no" ForcePerMachine="yes" EnableFeatureSelection="yes"/>
<MsiPackage Id="Driversx86" InstallCondition="NOT VersionNT64" SourceFile=".SRC\drivers32.msi" DisplayInternalUI="no" Visible="no" ForcePerMachine="yes" EnableFeatureSelection="yes"/>
</PackageGroup>
</Fragment>
And then, in the chain I just include the <PackageGroupRef Id="Drivers"/>
Things work as expected in that the engine correctly plans the installation based on the operating system.
The trouble I'm having is I want to display a list of packages that will be installed and I would like to:
determine from the custom bootstrapper whether a package is supposed to be visible to the UI or not, and maybe it's level
determine from the custom bootstrapper whether a package's InstallCondition evaluates to true of false
The bottom line though is I want to make sure my custom BA can obey what's declared in the bundle as far as what packages are allowed to be installed on the target system.
During runtime, there will be a file called BootstrapperApplicationData.xml. This file will contain information about each package, including InstallCondition (not sure when it was added, may require v3.10.3). You'll be able to pass the value of each condition to the Engine's EvaluateCondition method to determine whether it is true or false.
Related
In my Managed Bootstrapper Application I want to give the user the option to select which packages to install. Therefore I want to set a variable and pass it to the Wix Bootstrapper.
My approach was to do it similar like it is possible with the installfolder (described here) and check the value with the InstallCondition of the MsiPackage.
<Chain>
<MsiPackage ...
InstallCondition="[VariableName] = 1"
...>
</MsiPackage>
</Chain>
<Variable Name="VariableName" Type="numeric" Value="1"/>
Is this the right approach? If yes, has someone an example that works? If no, what is the best way to achieve that goal?
In our managed bootstrapper we provide the user UI to make a selection of the package they want to install.
Then this information from the model is propagated and handled in the OnPlanPackageBegin and OnPlanPackageComplete.
The package request state can be set to handle this.
I read and run sample from here.
Some questions:
How I can get actions names during the install/uninstall/remove process?
How I can pass variables and parameters to embedded MSI?
Is any way to get additional information from the embedded MSI (product version, company name etc) as it is done in WixSharp (WpfSetup sample)?
4. How I can get (set) from MSI file INSTALLFOLDER, TARGETDIR and other values?
I'm not sure you can or not. Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperApplication will tell you what msi package it is planning or executing, you may also be able to get information about which install action it is executing, check the events that get raised by this during your install process.
2.
In your bootstapper WPF app
//ba is an instance of BootstrapperApplication
this.ba.Engine.StringVariables["ServerInstallLoc"] = "YOUR DATA"
Bundle.wxs
<!-- Install paths provided by the managed bootstrapper interface -->
<Variable Name="ServerInstallLoc" bal:Overridable="yes" Type="string" Value=""></Variable>
And later reference this variable
<MsiPackage Id="MyInstaller" SourceFile="$(var.MyInstallerMsiProjectName.TargetPath)" Compressed="yes" DisplayInternalUI="no">
<!-- Pass wix bundle variable to MSI property -->
<MsiProperty Name="SERVER_INSTALL_OVERRIDE" Value="[ServerInstallLoc]"/>
</MsiPackage>
In your bootstrapper, you can reference properties of the bundled installers. the syntax is: !(bind.packageVersion.PackageName) assuming one of your <MsiPackage> elements is called PackageName. Binder variables reference
For question 4 look at this:
http://www.wrightfully.com/allowing-the-user-to-select-the-install-folder/
You can also look at the Wix managed bootstrapper as I believe it does this as well. You can download the source code here:
https://github.com/wixtoolset/wix3
Going from this answer https://stackoverflow.com/a/15985524/552448
<Wix>
<Bundle...>
<BootstrapperApplicationRef Id='WixStandardBootstrapperApplication.HyperlinkLicense' />
<Chain>
<MsiPackage SourceFile="prereq1.msi" />
....
<MsiPackage InstallCondition='NOT VersionNT64' SourceFile='path\to\x86.msi' />
<MsiPackage InstallCondition='VersionNT64' SourceFile='path\to\x64.msi' />
</Chain>
</Bundle>
</Wix>
All the projects in my solution target "Any CPU", with the exception of the bootstrapper and the MSI package, thus I'm using a shared cabinet to avoid doubling the final size of the bootstrapper.
I know I have to build the MSI with x86, then with x64 and finally build the bootstrapper. Did this manually and it works.
However, I'd like to automate these steps.
I've been trying to add a Prebuild event to the Bundle wixproj file, something along the lines of
$(MSBuildBinPath)\msbuild "$(SolutionDir)MyMSI\MyMSI.wixproj" /p:Platform=x86;Configuration=Release
$(MSBuildBinPath)\msbuild "$(SolutionDir)MyMSI\MyMSI.wixproj" /p:Platform=x64;Configuration=Release
However, this fails with this error:
The OutputPath property is not set for project 'MyLibrary.csproj'. Please check to make sure that you have specified a valid combination of Configuration and Platform for this project. Configuration='Release' Platform='x86'. You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn't exist for this project.
I'd like to make it work without having to go through all the projects in order to add the combination of platform/configuration. After all, this works if I right click MyMSI and choose build.
Surely I must be missing something.
It was pretty obvious - create two separate MSI projects - one with x86, the other with x64, both using the same files.
<ExePackage Id="PackageID1" DisplayName="xxx" Compressed="yes"
SourceFile="..\xxx\MyExe.exe" Vital="yes"
InstallCommand="parameters to the exe"
UninstallCommand="parameters to the exe"/>
When I trigger the Uninstall action:
this.Engine.Detect();
this.Engine.Plan(LaunchAction.Uninstall);
this.Engine.Apply(System.IntPtr.Zero);
The exePackage does not get invoked. However, during Install, it enters the exe package with the right parameters.
Am I missing something here?
You need a DetectCondition attribute on your ExePackage element. The DetectCondition is how the Burn engine determines if the package is installed on the machine or not. Without a DetectCondition the engine will think the package is never installed so it will never need to be uninstalled. Since all executables are different you have to provide your own DetectCondition. Usually the XxxSearch elements in the util namespace are helpful to detect if your executable is installed.
Note: you can see the 'plan' in the log file and it should show the PackageID1 package being detected as 'Absent' even though it is installed.
I have written a managed wix bootstrapper using WPF. The actual installation steps requires chaining of multiple msi's/exe's and batch files.
<Chain>
<MsiPackage SourceFile="xxx"/>
<ExePackage Id="Test" SourceFile="..\TestBatch.bat" Vital="yes"/>
<MsiPackage SourceFile="yyy"/>
</Chain>
During the execution of each package, a message should be displayed (preferably from the bootstrapper UI) indicating which msi/exe package/ batch file is being executed currently.
In short, a ProgressText is needed in the bootstrapper How can I make this happen?
Another question: I do not want all the msi's to be packaged into the bootstrapper exe. This is because: Each time an msi is changed we would like to ship only the updated/modified msi and not the entire bootstrapper exe. Is there a way to do this?
Two answers, one suggestion:
To get messages back during the MsiPackages being installed, handle the BootstrapperCore.ExecuteMsiMessage event. The event args there will contain a Message that contains the data you are looking for.
To configure how the packages are compressed or not, use the Compress attribute. You can either mark the entire Bundle/#Compress='no' or mark each package Compress='no' (or 'yes' if you want to go that way).
--
Suggestion: Be sure to add DetectCondition to the ExePackages so Burn will know if the ExePackages are already present or not.