Installer conditionally picking up files - wix

I'm building a Wix installer and I need two separate versions of said installer. One that picks up the latest development build of the project and one that picks up the latest release build. Currently my fragment looks like this:
<Property Id="Program.ReleaseBuild" Value="0" />
<?define ReleaseBuild = [Program.ReleaseBuild]?>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="InstallFolder">
<Component Id="TheExe" Guid="GUID_GOES_HERE">
<?if $(var.ReleaseBuild) = 1?>
<File Id="ProjectExe" Source="(Rel Project Path)/program.exe" />
<?else?>
<File Id="ProjectExe" Source="(Dev Project Path)/program.exe" />
<?endif?>
</Component>
</ComponentGroup>
</Fragment>
And I have a transform on the msi that transforms the file after build. But the problem is that the file is picked up on compile time not install time, so both version of the installer end up having the same file contained in them. Any idea how I can conditionally grab a dev file or a rel file in the same wix project?

If you want to create installation packages based on build quality (debug versus release), you can use two product configuration and select the source based on it. This way, you can run msbuild twice, one for each configuration. I don't understand the purpose of the transform you mentioned.
So here are steps you could take to accomplish this:
Create an empty solution.
Add your wixproj to it.
Add your csproj to it.
Add a reference of the csproj to the wixproj.
Modify your File[Source] to use the project reference, this way:
<File Source="$(var.MyProject.TargetPath)" Id="ProjectExe" />
The $(var.MyProject.TargetPath) will automatically get the exe from the correct path.
Create a batch file to run the msbuild twice, one for each configuration, with the following commands:
C:\> msbuild mySolution.sln /p:Configuration=Debug
C:\> msbuild mySolution.sln /p:Configuration=Release
The result will be two installation packages, one for each configuration.

Related

Wix Installer Is Copying a File During Build Instead of Install

I have a kind of strange issue that I've never run into before. I have a Wix installer that has the following fragment/component:
<Fragment>
<ComponentGroup Id="groupID">
<Component Id="componentID" Guid="a guid" Directory="a directory defined elsewhere">
<File Id="fileID" Source="$(var.mylibraryname.TargetPath)"/>
</Component>
</ComponentGroup >
</Fragment>
The issue is that the file defined above gets copied into the DirectoryRef when I build the Wix project, but it does not copy over when I install it. I do this type of thing pretty frequently, but have never seen this issue crop up. Why would Wix copy the file while being built? In every other instance , running the MSI does.

Wix Toolset - Variable Shared Across Projects/Solution

I am trying to share a variable across 2 of my wix projects but I am having issues.
Basically I am trying to accomplish having the version number of my bootstrapper and MSI in one file and then this referenced by the two projects.
I have three projects
Install - This is a setup project that creates an .msi file
Bootstrapper - This is a Wix Bootstrapper project that references and runs the .msi file at runtime
Shared - This is a wixlib project that contains a single variable in a fragment that is the version number
The shared project contains a single file i have called GlobalVars.wxs and looks like this
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<?define VersionNo = "6.86.123"?>
</Fragment>
</Wix>
The bootstrapper references this variable like this
<Bundle Name="ProgramName" Version="$(var.VersionNo)" Manufacturer="CompanyName" UpgradeCode="Guid" Compressed="no">
and the Install project references the variable like this - and has a reference to the .wxs from the shared project
<Product Id="*" Name="Program Name" Language="2057" Version="$(var.VersionNo)" Manufacturer="CompanyName" UpgradeCode="guid">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"/>
<?include GlobalVars.wxs ?>
Both projects have references setup to the wixlib project that contains the variable
When i attempt to build I am getting this error on both the install and bootstrapper project
Undefined preprocessor variable '$(var.VersionNo)'.
If the <?include?> tag resolved the issue I would expect the install project to build
Does anyone have any ideas as to what I might be doing wrong here?
To me it looks like the variable has not been defined by the time the build attempts to call it, but I am unsure as to show to change the order to ensure the variable is defined before anything else
Thanks for the help
I believe the answer to this question will help. I've used it and noticed that properties seem to be usable in my main wxs file.
To summarise, you need to set up a fake componentGroup in your library fragment, and use it in your installer. You do not need the include anymore, as long as the fake componentGroup from your fragment is referenced as a componentGroupRef in your main install, and your wixlib project is referenced in your installer project through VS (you said you'd already done this in your comments above).
Your library fragment might look something like this.
<Fragment id="fragment_id_may_not_be_needed">
<?define VersionNo = "6.86.123"?>
<ComponentGroup Id="c.define_version_num" />
</Fragment>
If the define for whatever reason doesn't work, try using a property instead. I'd be interested to know which works. Properties seem to work for me.
Then reference it in your main install like this:
<Feature Id="Main_installation" Title="Main installation" Level="1">
<!-- bringing in fragments from the shared libraries -->
<ComponentGroupRef Id="c.define_version_num" />
</feature>
Give it a whirl.

Include all Files in Bin folder in Wix installer

I'm new in Wix, I succefully create an MSI installer for my project, but my Bin folder have a lot of DLL's files with EXE main file, I want to include all these files with the installer
I found THIS solution, that seems right but unfortunately I can not accomplish this solution in my Wix file, Here's my Wix file:
<Product Id="*" Name="Setup"
Language="1033" Version="1.0.1.0"
Manufacturer="ORDER MS"
UpgradeCode="a4f0a0d0-ae64-4f62-9bb3-efa7e75072e0">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade Schedule="afterInstallInitialize"
DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="Setup" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentRef Id="ApplicationShortcutDesktop" />
<ComponentRef Id="ApplicationShortcut" />
</Feature>
<Icon Id="Icon.exe" SourceFile="$(sys.CURRENTDIR)\icon.ico"/>
<Property Id="ARPPRODUCTICON" Value="icon.exe" />
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="ProductComponent">
<File Source="$(var.Order.TargetPath)" />
</Component>
<Component Guid="A7C42303-1D77-4C70-8D5C-0FD0F9158EB4" Id="CopyComponent">
<CopyFile Id="SomeId"
SourceProperty="SOURCEDIRECTORY"
DestinationDirectory="CopyTestDir" SourceName="*" />
</Component>
</ComponentGroup>
I get this Error:
Error 1 ICE18: KeyPath for Component: 'CopyComponent' is Directory: 'INSTALLFOLDER'. The Directory/Component pair must be listed in the CreateFolders table.
This solution works with WIX 3.11.
To harvest an entire directory, you can use Heat from the WIX toolset. With Heat we can automatically include all files from a given source directory on every build. To do that we first need to edit the Setup.wixproj:
Define the Harvestpath for Heat:
<PropertyGroup>
<DefineConstants>HarvestPath=...\Deploy</DefineConstants>
</PropertyGroup>
Heat will create a .wxs file. So we need to add this file to the compile ItemGroup:
<ItemGroup>
<Compile Include="Product.wxs" /> <!-- This will be your default one -->
<Compile Include="HeatGeneratedFileList.wxs" /> <!-- This is the Heat created one -->
</ItemGroup>
Then execute Heat in the BeforeBuild build target:
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\Deploy"
PreprocessorVariable="var.HarvestPath"
OutputFile="HeatGeneratedFileList.wxs"
ComponentGroupName="HeatGenerated"
DirectoryRefId="INSTALLFOLDER"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)"
SuppressFragments="true"
SuppressRegistry="true"
SuppressRootDirectory="true" />
</Target>
This will generate the HeatGeneratedFileList.wxs every time the WIX installer is built. The directory ..\Deploy has to be set to the directory of the files to include.
The only thing we have to do to include these files in our installer is to edit the main .wxs file (like Product.wxs in this example). Heat will create a ComponentGroup with the given name from above. This component needs to be referenced in the Feature section of the Product.wxs:
<Feature Id="ProductFeature" Title="DiBA Tool" Level="1">
<...>
<ComponentGroupRef Id="HeatGenerated" />
</Feature>
I think you've gotten into a bit of a muddle, if you don't mind me saying so.
CopyFile will copy a file will copy a file from one place on a target machine (the machine where the install is being installed, not your development computer) to another folder on the same machine. I don't think this is what you want.
As Brian suggested you can use Heat to scan a folder and generate some code for you. You can use that in one of two ways:
As a development aid
Run the tool with this kind of command:
heat dir ".\My Files" -gg -sfrag -template:fragment -out directory.wxs
Then, take directory.wxs and use it as source code.
In the build pipeline
You can use the Heat tool in the build pipeline, so that compiling the install will generate the code.
Contrary to Brian's suggestion, if you are using MSBuild I would suggest the HarvestDirectory target. Here's what I have where I am doing something similar:
<HarvestDirectory Include="$(MyHarvestDirectory)">
<InProject>false</InProject>
<PreprocessorVariable>var.MyHarvestDirectory</PreprocessorVariable>
<ComponentGroupName>MyComponentGroup</ComponentGroupName>
<DirectoryRefID>MY_DIRECTORY_ID</DirectoryRefID>
</HarvestDirectory>
This will feed an item into the HarvestDirectory target and make sure it's all handled in the correct way. This code just goes into an ItemGroup in your .wixproj. (If you're not sure how to tweak your project file, check out this video)
Of course, this assumes you are using MSBuild (or Visual Studio, because that uses MSBuild).
Caveat
Having said all this, if the main issue is simply that there are lots of files, I would simply say knuckle down and just define the list. Use the Heat tool as a scaffold if you like, but there's no substitute for just learning the language and working with it. Trying to do things with auto generated code can introduce subtle issues, and it's always simpler to work with a static list.
I do something similar to what you require here during my installation. I need to copy the contents of a folder with 1000+ files in it (the help files).
What I did to solve this is the following:
In the Installer.wixproj I defined the following:
<Target Name="BeforeBuild" >
<Exec Command=""$(WixToolPath)Heat.exe" dir "$(MSBuildThisFileDirectory)\$(Configuration)\bin" -ag -cg BinDir -dr BIN -template fragment -sreg -sfrag -srd -var var.BinDir -o "$(MSBuildThisFileDirectory)\Components\Bin.wxs"" Condition="!Exists('$(MSBuildThisFileDirectory)\Components\Bin.wxs')" />
</Target>
And this will run heat on the $(Configuration)\bin\ dir and generate a wxs file including ALL the files in the bin dir.
This way if you add or delete any binaries in your bin dir it will automatically get picked up when you rebuild your installer (if the Bin.wxs file doesn't exist).
Now you need to make sure you define the variable "BinDir" for wix which points to the bin dir on the build machine. You also need to add the Bin.wxs file to your wixproj as a link (when adding existing file there's a tiny arrow drop down on "Add". Click that and select "Add as link".)
I think there's an actual heat target somewhere in wix but I haven't looked through that enough to know how to use it yet.
As an alternative to the other answers:
There is a Visual Studio extension called Wax (GitHub, Visual Studio Marketplace):
It provides an alternative way to handle all the required files with GUI.
It may be not as sophisticated as command-line tools like heat, but it is much simpler and can be a nice and friendly tool in the beginning, when you just start learning WiX - and want a quickstart.

Set date of installed files with WiX

Is it possible to from the wix-project set the timestamp of Files?
I am thinking like:
<File Id='id1' LastModified='2015-11-26' />
or
<File Id='id1' LastModified='[Now]' />
There is no simple way using wix file element, no attribute that specify the version.
You can check all the attribute in:
http://wixtoolset.org/documentation/manual/v3/xsd/wix/file.html
This open source project contain many useful scripts and build custom activities, the link below is for the prebuild script.
https://github.com/tfsbuildextensions/CustomActivities/tree/master/Source/Scripts

How to include prerequisites with msi/Setup.exe in WIX

I'm trying to combine my package in a single setup EXE file and upload it to the Internet.
I have created a Microsoft bootstrapper that contains Setup.exe with project MSI output, and pre-requisite .NET Framework 2.0, Windows Installer 3.1 , Visual C++ 2005 redistributables, and Microsoft ReportViewer. I have created a setup project using Visual Studio 2008.
Now I'm trying to create a single compressed setup using WiX 3.6. I have installed it in Visual Studio 2008.
I have attached the setup.exe and MSI file using following commands.
<ExePackage SourceFile ="setup.exe" Compressed ="yes"/>
<MsiPackage SourceFile ="myproject.msi" Compressed ="yes" />
But it is unable to find the MSI file. How can I include the above prerequisites with it?
Or can I download the above prerequisites from the Internet while installing? How do I do it?
I have removed the default setup.exe from Visual Studio and used the MSI file and dependencies from Visual Studio to create a WiX 3.6 Bootstrapper:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="My Application"
Version="1.0"
IconSourceFile ="E:\logo.ico"
Manufacturer="My company"
UpgradeCode="4dcab09d-baba-4837-a913-1206e4c2e743">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication
LicenseFile="E:\License.rtf"
SuppressOptionsUI ="yes"
LogoFile ="logo.ico" />
</BootstrapperApplicationRef>
<Chain>
<ExePackage
SourceFile ="ReportViewer\ReportViewer.exe"
Compressed ="yes"
Vital ="no"
Permanent ="yes"/>
<ExePackage
SourceFile ="vcredist_x86\vcredist_x86.exe"
Compressed ="yes"
Vital ="no"
Permanent ="yes"/>
<MsiPackage
SourceFile ="MySetup.msi"
Compressed ="yes"
DisplayName ="My Application"
ForcePerMachine ="yes"/>
</Chain>
</Bundle>
</Wix>
It compresses into an single EXE file with prerequisites.
SourceFile will accept a relative path the .msi file. Or, if you are building the .msi file with a WiX Setup project, you can add a reference to the Setup project in the WiX Bootstrapper project. That defines variables you can use like this:
<MsiPackage SourceFile ="$(var.myproject.TargetPath)" Compressed ="yes" />
Your users will probably have a better experience if you drop the Visual Studio Bootstrapper and put all prerequisites in the WiX Bootstrapper. It'll be a little more work for you because there isn't a pre-defined ExePackageGroup or ExePackage for all of your project's prerequisites.
The best place to check for information on what should go into an ExePackage definition is the documentation for the particular prerequisite in question. But, it is also instructive to compare with the Visual Studio Bootstrapper packages (in, e.g., C:\Program Files\Microsoft Visual Studio 9\SDK\v2.0\Bootstrapper\Packages) and similar prerequisites that might be predefined in the WiX source code. In particular, in the WiX source code, you will find an ExePackage that downloads .NET 4 from the Internet if needed while installing.
You can include some pre-requisite file with something like:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="MyApplication" Version="$(var.ProductVersion)" Manufacturer="manuf" Language="1033">
[...]
<Directory Id="ANOTHERLOCATION" Name="MyApplicationName">
<Component Id="ApplicationFiles" Guid="12345678-1234-1234-1235-111111111111">
<File Id="ApplicationFile4" Source="C:\Users\user\Desktop\requisite.exe"/>
<CreateFolder />
</Component>
</Directory>
<SetDirectory Id="ANOTHERLOCATION" Value="[WindowsVolume]MyApp" />
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="ApplicationFiles" />
</Feature>
</Product>
</Wix>
The above copies the requisite.exe file inside C:/MyApp.
You then have to run the requisite.exe file from your program based on some conditions.
This is the most basic and straight-forward way without using complicated Wix wizardry.
You can use something like NSIS to wrap up your bootstrapper and MSI. You'll need to write a simple NSIS script, like this:
!define PRODUCT_NAME "YourProductNameHere"
Name "${PRODUCT_NAME}"
OutFile "SetupWrapper.exe"
Icon "Setup.ico"
BrandingText " "
SilentInstall silent
Section
SetOutPath "$TEMP\${PRODUCT_NAME}"
; Add all files that your installer needs here
File "setup.exe"
File "product.msi"
ExecWait "$TEMP\${PRODUCT_NAME}\setup.exe"
RMDir /r /REBOOTOK "$TEMP\${PRODUCT_NAME}"
SectionEnd
Save this to a file named SetupWrapper.nsi, and edit the product name and paths to setup.exe and your MSI file. Now you can build this file to get a single EXE file that contains the bootstrapper and the MSI.
When this EXE is run, it will not have any UI of its own -- it will simply extract your bootstrapper and MSI to a temp folder, then execute the bootstrapper, and clean up afterwards.
You can also add a post-build step to your project to build this wrapper, which will automatically generate the combined wrapper EXE. To do this, you can add a command like this:
path-to-NSIS\nsis-2.46\makensis.exe /V2 your-project-path\SetupWrapper.nsi