It took me far too long to put this together, so I'm sharing it here.
My installer needs to work without access to the internet.
Starting with the WixSharp Setup - Bootstrapper Visual Studio template, here is one working method for building an installer that contains the .NET 4.5 (or 4.0) redist file.
My installer needs to work without access to the internet.
Starting with the WixSharp Setup - Bootstrapper Visual Studio template, here is one working method for building an installer that contains the .NET 4.5 (or 4.0) redist file.
using System;
using System.Xml.Linq;
using WixSharp;
using WixSharp.Bootstrapper;
namespace SetupBootstrapper {
class Program {
static void Main() {
string productMsi = BuildMsi();
// To make a self contained installer, it isn't enough to switch from
// new PackageGroupRef("NetFx40Web")
// to
// new PackageGroupRef("NetFx40Redist")
// because the installer still won't contain the redistributable file.
// It will be downloaded when the installer runs.
//
// This sample was constructed by taking the values for variables, registry searches and the ExePackage properties from the NetFxExtension source found here:
// http://wix.codeplex.com/SourceControl/latest#src/ext/NetFxExtension/wixlib/NetFx4.5.wxs
//
// You can follow a link like the one in this line to download the actual file (50MB):
// <?define NetFx45RedistLink = http://go.microsoft.com/fwlink/?LinkId=225702 ?>
//
// If you can arrange for the file to be in the "redist" folder next to your installer when it runs,
// then you can simply stick with new PackageGroupRef("NetFx40Redist"), as it will look there before dowloading
// from the URL.
//
// I couldn't figure out an easy way to arrange for this to happen, so I replicated the Fragment containing "NetFx45Redist".
// There are three parts to it:
// 1. The RegistrySearch: Defined below by bootstrapper.AddWixFragment.
// 2. The ExePackage: Defined below in the Bundle instead of the PackageGroupRef.
// 3. The WixVariables: Added below in a bootstrapper.WixSourceGenerated event handler.
//
// If the variables WixMbaPrereqPackageId and WixMbaPrereqLicenseUrl aren't assigned you'll get two build errors.
var bootstrapper =
new Bundle("MyProduct"
/* Only .NET 4 is required by the bootstrapper. I needed 4.5 so that's enabled in this sample.
, new ExePackage {
InstallCommand="/q /norestart ", // /ChainingPackage \"[WixBundleName]\"",
RepairCommand="/q /norestart /repair", // /ChainingPackage \"[WixBundleName]\"",
UninstallCommand="/uninstall /q /norestart", // /ChainingPackage \"[WixBundleName]\"",
PerMachine=true,
DetectCondition="MYNETFRAMEWORK40",
Id="MyNetFx40Redist",
Vital=true,
Permanent=true,
//Protocol="netfx4",
SourceFile = @"redist\dotNetFx40_Full_x86_x64.exe",
Compressed=true,
Name=@"redist\dotNetFx40_Full_x86_x64.exe"
}
*/
, new ExePackage {
InstallCommand = "/q /norestart ",
RepairCommand = "/q /norestart /repair",
UninstallCommand = "/uninstall /q /norestart",
PerMachine = true,
DetectCondition = "MYNETFRAMEWORK45 >= 378389",
Id = "MyNetFx45Redist",
Vital = true,
Permanent = true,
//Protocol="netfx4",
SourceFile = @"redist\dotnetfx45_full_x86_x64.exe",
Compressed = true,
Name = @"redist\dotnetfx45_full_x86_x64.exe"
}
, new MsiPackage(productMsi) { DisplayInternalUI = true });
bootstrapper.AddWixFragment("Wix/Bundle"
, new UtilRegistrySearch {
Root = Microsoft.Win32.RegistryHive.LocalMachine,
Key = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full",
Value = "Install",
Result = SearchResult.value,
Variable = "MYNETFRAMEWORK40",
}
, new UtilRegistrySearch {
Root = Microsoft.Win32.RegistryHive.LocalMachine,
Key = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full",
Value = "Release",
Result = SearchResult.value,
Variable = "MYNETFRAMEWORK45",
}
);
bootstrapper.IncludeWixExtension(WixExtension.Util);
bootstrapper.Version = new Version("1.0.0.0");
bootstrapper.UpgradeCode = new Guid("6f330b47-2577-43ad-9095-1861bb25844b");
bootstrapper.Application = new SilentBootstrapperApplication();
bootstrapper.PreserveTempFiles = true;
bootstrapper.WixSourceGenerated += document => {
var root = document.Root;
root.Select("Bundle").AddElement("WixVariable", @"Id=WixMbaPrereqPackageId;Value=MyNetFx45Redist");
root.Select("Bundle").AddElement("WixVariable", @"Id=WixMbaPrereqLicenseUrl;Value=http://go.microsoft.com/fwlink/?LinkID=260867");
};
bootstrapper.Build("MyProduct.exe");
}
static string BuildMsi() {
var project = new Project("MyProduct",
new Dir(@"%ProgramFiles%\My Company\My Product",
new File("Program.cs")));
project.GUID = new Guid("6fe30b47-2577-43ad-9095-1861ba25889b");
//project.SourceBaseDir = "<input dir path>";
//project.OutDir = "<output dir path>";
return project.BuildMsi();
}
}
}