WiX msxml 6 prerequisite - wix

I am creating a WiX installer for our software which requires msxml 6. If I understand correctly msxml 6 is shipped with Windows starting from XP SP3 but since our software supports all versions of XP I guess there is a risk that the customer won't have msxml 6 installed; thus I would like msxml 6 to be installed by our installer if it is not already installed.
I found this page that shows how to detect if msxml 6 is installed on the computer but it doesn't say which version (SP1, SP2 etc.) is installed.
My question is how do I properly detect if msxml 6 is installed and install the latest version if it is not detected?
This is what I am using now to perform the detection (a combination of what I found in the link above and what I use for other prerequisites):
<!-- MSXML6 SP1 (x86) -->
<util:RegistrySearch Root="HKCR" Key="Msxml2.DOMDocument.6.0" Format="raw"
Variable="MsXml6x86Installed" />
<PackageGroup Id="MsXml6x86">
<MsiPackage Id="MsXml6x86" Cache="no" Compressed="yes" Permanent="yes" Vital="yes"
SourceFile="$(var.PrerequisitesPackagesRootPath)\msxml6_SP1_x86\msxml6_x86.msi"
InstallCondition="(VersionNT < v6.0) AND (NOT MsXml6x86Installed)" />
</PackageGroup>
<!-- MSXML6 SP1 (x64) -->
<util:RegistrySearch Root="HKCR" Key="Msxml2.DOMDocument.6.0" Format="raw"
Variable="MsXml6x64Installed" Win64="yes" />
<PackageGroup Id="MsXml6x64">
<MsiPackage Id="MsXml6x64" Cache="no" Compressed="yes" Permanent="yes" Vital="yes"
SourceFile="$(var.PrerequisitesPackagesRootPath)\msxml6_SP1_x64\msxml6_x64.msi"
InstallCondition="(VersionNT64 < v6.0) AND (NOT MsXml6x64Installed)" />
</PackageGroup>
And in my Bundle (x86):
<Bundle>
...
<Chain>
<PackageGroupRef Id="MsXml6x86"/>
<PackageGroupRef Id="Vc2010Sp1x86" />
<PackageGroupRef Id="Netfx35Sp1" />
<PackageGroupRef Id="Netfx4Full" />
...
</Chain>
</Bundle>
When I start my installer I get the following output in the log file:
[21E4:3F00][2015-02-11T09:57:31]i000: Setting string variable 'MsXml6x86Installed' to value 'XML DOM Document 6.0'
[21E4:3F00][2015-02-11T09:57:31]i101: Detected package: MsXml6x86, state: Absent, cached: None
So the registry key I search for is found which suggests msxml 6 exists but the actual package does not. I guess the reason is that when I search for the msxml6.dll my Win 7 computer appears to have SP3 installed while the msxml package I am using in the installer is for SP1? But this is where I don't know what to do; on our Win 7 test computer msxml 6 SP3 is installed by default and our Win XP SP3 test computer has msxml 6 SP2 installed by default. Which msxml package should I use in the installer in order to get a solution for all versions of Windows starting from XP? I am not able to find a download link to SP3 or SP2 om Microsoft's website.
I appreciate any help.

I don't believe the page you linked is very well thought out. What you need to do (in general) is observe the footprint of any given prereq and make the best choice on how to detect it. For MSXML6 I edited the MSI using ORCA and found the following in the registry table:
SOFTWARE\Microsoft\MSXML 6.0 Parser and SDK\CurrentVersion
PatchLevel = 6.00.3883.8
I would go find different sp levels of that MSI and see if you find a trend and then use that in your logic.
Otherwise it is very sound and reasonable approach to put a business/engineering requirement of XP SP3 on your application. If a customer is going to run a legacy OS they should atleast be up to the latest SP. Microsoft has cut off XP of Windows Update and you are on very solid ground to no longer support this OS. The result would be a simpler more reliable installer with less development and test costs.

Related

common installe r to set registry value in 64 bit and 32 bit system?

I have a registry value setter in my wix application as follows
<Component Id="EngageAssistanceAutostart" Guid="f9e92a81-506d-4fe9-836b-564420a98ea1" Win64="yes">
<RegistryValue Id="crimsonwatchdog" Root="HKLM" Action="write"
Key="Software\Microsoft\Windows\CurrentVersion\Run"
Name="Crimson watch dog"
Value="[INSTALLFOLDER]Crimson.Watchdog.exe"
Type="string" />
as you can see, to edit registry in windows 64 bit system, I have kept win64="yes"
and I also have to set patform="x64"
<Package InstallerVersion="200" Platform="x64" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" AdminImage="yes" />
if I didn't do this I wont be able to set reg. value in 64bit system.
if I do this, this installer wont work in 32bit system.
is there any solution which will allow me to set registry value in both 64 and 32 bit system?
You don't need to set platform to x64 to create registry in 64bit hive.
Component will decided where this registry will be created.
In your case, because it's only RUN key, you should create single component that is not set to x64.
What MSI will do whit such component.
On x86 machine, registry key will be created in standard location.
On x64 machine, registry key will be created under Wow6432Node but for Run this should be not a problem.

Wix Toolset prerequisites: Check for .Net Framework

I have a wix bundle project that I am editing (ver 3.10). I am trying to use the wixnetfxextensions to install .net framework 4.6 if it is not already installed. I created an exepackage that uses the WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED property. I'm guessing I am not using this correctly. Any help on how to use that? Currently the .net framework will not install not matter what.
<Chain>
<PackageGroupRef Id="redist_vc140" />
<PackageGroupRef Id="NetFx461Full" />
<MsiPackage Id="MSI_Installer" SourceFile="C:\Installer.msi"/>
</Chain>
<Fragment>
<PropertyRef Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED"/>
<!-- Install .NET 4.6.1 -->
<PackageGroup Id="NetFx461Full">
<ExePackage Id="NetFx461"
DisplayName="Microsoft .NET Framework 4.6.1"
Compressed="no"
Cache="yes"
PerMachine="yes"
Permanent="yes"
Protocol="netfx4"
Vital="yes"
SourceFile="..\NDP461-KB3102436-x86-x64-AllOS-ENU.exe"
UninstallCommand="/q /norestart"
RepairCommand="/q /norestart"
DetectCondition="NOT WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED" />
</PackageGroup>
</Fragment>
You're doing a lot of extra work to install .net that you don't actually need to do.
To add .net 461 to your installer just include the netfxextension and add
<Bundle>
<PayloadGroup Id="NetFx461RedistPayload">
<Payload Name="redist\NDP461-KB3102436-x86-x64-AllOS-ENU.exe"
SourceFile="C:\path\to\redists\in\repo\NDP461-KB3102436-x86-x64-AllOS-ENU.exe"/>
<PayloadGroup/>
</Bundle>
so that the full installer is included in your bootstrapper. You can ignore this and then the bootstrapper will download the installer but if the customer doesn't have an internet connection they won't be able to install .net.
Then in your chain just add
<PackageGroupRef Id="NetFx461Redist"/>
I used this as a reference and checked the wix source to see what the
name of .net 461 being used is in netfxextension.
Sean Hall mentioned that bundles don't even use properties so what I had written here doesn't apply at all in this situation. (And it was also incorrect)
Did what Brian Sutherland suggested: Added the WxsVariable that compares the .netframework with the determined minimum release number. then make that a detectcondition in the exepackage

Using WiX, how can I download a dependency when the initial URL failed to download

I'd like to provide my WiX bundle an alternate download(s) URL for grabbing dependencies. I haven't been able to track down documentation on this scenario, so I don't even know if it's possible outside of a hackish Custom Action workaround. Right now, when any attempted download fails, the installation fails, as intended. I'd like it to simply try the next URL(s) with public or internal mirrors if the initial attempt fails until it either succeeds or hard-fails from none of them working. I already have normal dependency packages implemented. I'm just not sure where to go from here to achieve this design. I'd like to do it outside of custom actions, if possible.
Current code example:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Fragment>
<!-- Check registry keys for Microsoft Visual C++ 2005 Redistributable -->
<util:RegistrySearch Root="HKLM"
Key="SOFTWARE\Classes\Installer\Products\1af2a8da7e60d0b429d7e6453b3d0182"
Result="exists"
Variable="MVC2005Present_x64"
Win64="yes"/>
<!-- Package to deploy Microsoft Visual C++ 2005 Redistributable (x64) -->
<ExePackage Id="MVC2005Exe_x64"
Name="Microsoft Visual C++ 2005 Redistributable Package (x64)"
Cache="no"
Compressed="no"
PerMachine="yes"
DownloadUrl="https://download.microsoft.com/download/8/B/4/8B42259F-5D70-43F4-AC2E-4B208FD8D66A/vcredist_x64.EXE"
Permanent="yes"
InstallCommand="/q"
RepairCommand="/q"
DetectCondition="MVC2005Present_x64"
InstallCondition="DeployDependencies = 1">
<RemotePayload CertificatePublicKey="5C499B10F7EF186DC729991A262AB52066423909"
CertificateThumbprint="93859EBF98AFDEB488CCFA263899640E81BC49F1"
Description="Microsoft Visual C++ 2005 Redistributable (x64) Setup"
Hash="EE916012783024DAC67FC606457377932C826F05"
ProductName="Microsoft Visual C++ 2005 Redistributable (x64)"
Size="3175832"
Version="6.0.2900.2180" />
<ExitCode Behavior="scheduleReboot" Value="1641" />
<ExitCode Behavior="scheduleReboot" Value="3010" />
</ExePackage>
</Fragment>
</Wix>
Burn supports one download URL per payload. A custom bootstrapper application gets an OnResolveSource callback where it can supply an alternate download location when the one authored in the bundle fails.

WIX Install .NET and VSTO if Admin, fail early if non-Admin

I'm trying to deploy an Excel plug-in to the mass market. The plug-in requires VSTO runtime (vstor_redist.exe) and .NET 4.5 (for 64 bit OS) or .NET 4.0 (for 32 bit OS). I'm willing to assume that potential users already have at least .NET 2.0. Currently my setup consists of:
Separate 32 bit and 64 bit WIX .msi installers which install the plug-in in per-user mode.
Separate 32 bit and 64 bit bootstrapper bundles which wrap each .msi and install VSTO runtime and .NET as shown in the code below:
<util:RegistrySearch Id="VSTORuntimeTest" Root="HKLM" Key="SOFTWARE\Microsoft\VSTO Runtime Setup\v4R\" Value="VSTORFeature_CLR40" Variable="VSTORFeature"/>
<util:RegistrySearch Id="VSTORuntimeVersionV4R" Root="HKLM" Key="SOFTWARE\Microsoft\VSTO Runtime Setup\v4R\" Value="Version" Variable="VSTORVersionV4R"/>
<util:RegistrySearch Id="VSTORuntimeVersionV4" Root="HKLM" Key="SOFTWARE\Microsoft\VSTO Runtime Setup\v4\" Value="Version" Variable="VSTORVersionV4"/>
<Chain>
<!-- Install .Net 4.0 or 4.5, depending on build -->
<?ifdef x64?>
<PackageGroupRef Id="NetFx45Web" />
<?endif ?>
<?ifdef x86?>
<PackageGroupRef Id="NetFx40Web" />
<?endif ?>
<RollbackBoundary />
<!-- Install VSTO runtime -->
<ExePackage Id="VSTORuntime" SourceFile="..\resources\vstor_redist.exe" Permanent="yes" Vital="yes" Cache="no" Compressed="no"
DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=158917"
PerMachine="yes"
InstallCommand="/q /norestart"
DetectCondition="VSTORFeature"
InstallCondition="NOT VSTORFeature OR NOT (VSTORVersionV4R >=v10.0.40303) OR NOT (VSTORVersionV4 >=v10.0.21022)" />
<RollbackBoundary />
<?ifdef x64?>
<MsiPackage
Id="nx_msi_package_version"
SourceFile="..\My 64 bit Setup.msi"
Compressed="yes"
Vital="yes" />
<?endif ?>
<?ifdef x86?>
<MsiPackage
Id="nx_msi_package_version"
SourceFile="..\My 32 bit Setup.msi"
Compressed="yes"
Vital="yes" />
<?endif ?>
</Chain>
A .NET 2.0 wrapper which includes both the bootstrappers as embedded resources and deploys & runs the correct bootstrapper for the client OS. (Essentially Yochai Timmer's answer in Single MSI to install correct 32 or 64 bit c# application)
The whole thing feels like a turducken, but it works nicely for both silent upgrades and for fresh installs when the user has admin credentials. But if the user is not an admin and does not yet have both VSTO and the appropriate .NET installed, it fails ungracefully with the error: "0x8007051b - This security ID may not be assigned as the owner of the object" after a long download process.
What I would like to do is check in advance whether the user needs to ask an administrator to intervene and install VTSO and/or .NET for them, and display a message, ideally with website link(s), when this is the case. This check could be in the bootstrapper, or in my .NET 2.0 wrapper. Any recommendation on how best to do this?
Thanks, Eric
The best way for me was to do the work in my 32-bit C# wrapper. As the code in my question indicates, Burn doesn't appear to offer any built-in package with VSTO support -- instead I'm just reading the registry manually and basing my logic on that. Burn does offer pre-built packages for .NET 4.0 and .NET 4.5, but I didn't see an easy way to support Fail Early with these.
My C# 2.0 wrapper now includes the following logic:
private static bool NeedsMorePermissionToInstallPrerequisites(out string error)
{
error = string.Empty;
// Is user an admin? If so, we're OK
if (PrivilegeTester.CanBeAdmin())
{
return false;
}
// Is .NET already installed?
bool isDotNetInstalled;
string dotNetVersion;
if (Is64BitOperatingSystem())
{
isDotNetInstalled = PrereqSoftwareChecker.IsDotNet45Installed();
dotNetVersion = "Microsoft .NET 4.5";
}
else
{
isDotNetInstalled = PrereqSoftwareChecker.IsDotNet40Installed();
dotNetVersion = "Microsoft .NET 4.0";
}
// Is VTSO already installed?
bool isVtsoInstalled = PrereqSoftwareChecker.IsVstoRuntimeInstalled();
if (isVtsoInstalled && isDotNetInstalled)
{
return false;
}
// If we got this far, there's trouble. Build the error.
[...]
Here the CanBeAdmin() functionality is based on Calling IPrincipal.IsInRole on Windows 7, and the IsVstoRuntimeInstalled() looks at the exact same set of registry keys that I use in my VSTORuntimeTest, etc. logic in my original question. The .NET checks also look at the registry, using keys that are well documented in MSDN. For example:
internal static bool IsDotNet40Installed()
{
try
{
Version dotnet4Version = new Version(GetHKLMValue("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4.0\\Client", "Version").ToString());
return dotnet4Version >= new Version("4.0.0.0");
}
catch
{
return false;
}
}
private static object GetHKLMValue(string key, string valueName)
{
return Registry.GetValue("HKEY_LOCAL_MACHINE\\" + key, valueName, null);
}
It would be nice if Burn could handle something like this better, but it might be complicated, since simply providing a Fail Early .NET package and a separate Fail Early VSTO package would not be enough to build a full list of packages that would need to be installed independently by an administrator.
Using C# and .NET 2.0 in bootstrapper-wrapper code is obviously a risk here, but I'm guessing that there aren't too many old XP boxes out in the wild that have Office and don't have at least .NET 2.0.

How to intelligently install .NET 4.x using WiX Burn

When installing an application that can use either .NET 4.0 or 4.5, what is the best practice when installing the prerequisites .NET framework? And how do you implement it using Burn in WiX?
These are the options and trade-offs that I am aware of:
Option 1: Install .NET 4.0 (just what you need)
Advantages: None known (except for Windows XP, where this is the only choice)
Option 2: Install .NET 4.5 if .NET 4.5 is not present
Advantages: User won't have to install .NET 4.5 later for future
apps. App won't experience a .NET version change when user later does
upgrade to .NET 4.5. App immediately gets performance improvements of
.NET 4.5.
Option 3: Install .NET 4.5 only if neither .NET 4.x is present
Advantages: Much faster deployment than option 2 if .NET 4.0 is
already installed. If it's not, then the advantages of option 2
apply.
As far as I can tell, the best practice would be option 2 if the performance improvements are important and option 3 if average deployment speed is important. Does this sound right? Am I missing any advantage to option 1? Most importantly, if option 3 does make sense, how do you implement it using Burn when installing .NET from the web?
Below is how I detect .NET in my bundle. Note the use of DetectConditions and InstallConditions. The DetectCondition will check whether or not the specific package is installed, whereas the InstallCondition can be used to override the DetectCondition to specify when the package should be installed. For example, on XP you can't install .NET 4.5 so my InstallCondition prevents installation in such a case.
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full" Value="Version" Variable="Netfx4FullVersion" />
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full" Value="Version" Variable="Netfx4x64FullVersion" Win64="yes" />
<!-- .NET 4.5 only installed if Vista or higher AND it's not already installed-->
<PackageGroup Id="Netfx45">
<ExePackage Id="Netfx45" Cache="no" Compressed="yes" PerMachine="yes" Permanent="yes" Vital="yes" InstallCommand="/q"
SourceFile="C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX45Full\dotnetfx45_full_x86_x64.exe"
DetectCondition="(Netfx4FullVersion="4.5.50709") AND (NOT VersionNT64 OR (Netfx4x64FullVersion="4.5.50709"))"
InstallCondition="(VersionNT >= v6.0 OR VersionNT64 >= v6.0) AND (NOT (Netfx4FullVersion="4.5.50709" OR Netfx4x64FullVersion="4.5.50709"))"/>
</PackageGroup>
<!-- .NET 4.0 only installed if XP AND it's not already installed -->
<PackageGroup Id="Netfx4Full">
<ExePackage Id="Netfx4Full" Cache="no" Compressed="yes" PerMachine="yes" Permanent="yes" Vital="yes" InstallCommand="/q"
SourceFile="C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX40\dotNetFx40_Full_x86_x64.exe"
DetectCondition="Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)"
InstallCondition="(VersionNT < v6.0 OR VersionNT64 < v6.0) AND (NOT (Netfx4FullVersion OR Netfx4x64FullVersion))"/>
</PackageGroup>
Then if you want to install one of the packages, just reference it in your chain:
<Chain>
<PackageGroupRef Id='Netfx45'/>
</Chain>
With regards to your specific question, I would install whatever framework version the application was tested against. If tested against both .NET 4.0 and .NET 4.5 I suppose it is a judgement call, however I would try to simplify the setup experience as much as possible. So if .NET 4.0 were already installed and the application does not require .NET 4.5, I would not install it.
Also, there is a disadvantage to Option 2 if you are using a custom Managed Bootstrapper Application. Let's say you have .NET 4.0 installed and your managed bootstrapper requires .NET 4.0 (or greater). When you run the installer it will install .NET 4.5 which replaces .NET 4.0, forcing your installer to reboot halfway through because it was using .NET framework at the same time it was being updated. Again, this is only an issue if you are using your own custom managed bootstrapper.