WIX - Major Upgrade Uninstalling files it didn't install - wix

I have divided my WIX installer into 2 primary MSI's, one is large and is rarely updated and the other is small and frequently updated.
They both install to the same directory (ie ..program files/MyCompany/MyProduct/), the issue I am having is that on an upgrade of the smaller installer the files from the large installer are being removed.
How can I prevent the smaller MSI installer from removing the larger MSI installer files on a Major upgrade? The bootstrapper detects (reg check) if the larger MSI is required and will download it as required and the smaller is assumed to always be required.
I am using WIX 3.6 with the default burn bootstrapper.
Bootstrapper:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:netfx='http://schemas.microsoft.com/wix/NetFxExtension'>
<Bundle Name="MyProduct" Version="4.0.6156" Manufacturer="MyCompany" UpgradeCode="cc5f7c9c-8e02-42b7-b202-a3b0865686c5" DisableModify="yes" DisableRepair="yes" UpdateUrl="URI TO SETUP">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense" />
<WixVariable Id="WixStdbaLicenseUrl" Value="URI TO LICENSE AGREEMENT" />
<WixVariable Id="WixStdbaLogo" Value="ClientLogo.png" />
<util:RegistrySearch Id="NetDetect"
Variable="NetFramework"
Root="HKLM"
Key="Software\Microsoft\NET Framework Setup\NDP\v4\Full"
Value="Install" />
<util:ProductSearch Result="version" Guid="DF6C4673-A1B6-419F-B514-DBC096E6CFA8" Variable="ImgagingVersion"/>
<Chain>
<ExePackage Compressed="no"
DownloadUrl="URI TO DOT NET INSTALLER"
Id="DotNet4Install"
InstallCondition="NetFramework <> 1"
SourceFile="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX40\dotNetFx40_Full_x86_x64.exe"
Permanent="yes"
InstallCommand="/q /norestart /ChainingPackage "MYPRODUCT""
PerMachine="yes"
Vital="yes"/>
<MsiPackage Compressed="no"
DownloadUrl="URI TO LARGER INSTALLER"
Id="ImagingInstaller"
InstallCondition="ImgagingVersion < v1.0.0.0"
SourceFile="$(var.WIX.Setup.Accusoft.TargetDir)\LargeInstaller.msi"
Vital="yes"
/>
<MsiPackage Compressed="no"
DownloadUrl="URI TO SMALLER INSTALLER"
Id="ClientServiceInstall"
SourceFile="$(var.WIX.Setup.Client.TargetDir)\SmallInstaller.msi"
Vital="yes"/>
</Chain>
</Bundle> </Wix>

Ok the issue I was having was because I was incrementing the version of the boot strapper on every update of the smaller msi installer, instead I am now only incrementing the version number of the msi.

Related

Web download of vcruntime140 with wix burn

I want to use the WiX bootstrapper burn to automatically download and install the vcruntime140 package (Visual C++ Redistributable for Visual Studio 2015) if it is required.
It's trivially easy to do this for the .NET frameworks:
<Chain>
<PackageGroupRef Id="NetFx452Web"/>
...
</Chain>
but I can't find an equivalent for the vcruntime packages. (Is that because there isn't one, or am I just typing the wrong keywords into Google?)
Just to be clear: I do not want to include the package with my installer. It must be a web download.
There is no PackageGroupRef for the redist as for .net.
But there is 3 other options:
Add a redist exe in your chain. (Not good for you)
Use a redist c++ merge module inside one of your msi's.
Try to write your own web download as .net does. Here is a sample of the .net web download. The full file can be found in the source code of wix by the name "NetFx46.wxs"
<Fragment>
<PropertyRef Id="WIXNETFX4RELEASEINSTALLED" />
<Property Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED" Secure="yes" />
<SetProperty Id="WIX_IS_NETFRAMEWORK_46_OR_LATER_INSTALLED" Value="1" After="AppSearch">
WIXNETFX4RELEASEINSTALLED >= "#$(var.NetFx46MinRelease)"
</SetProperty>
</Fragment>
<Fragment>
<util:RegistrySearchRef Id="NETFRAMEWORK45"/>
<WixVariable Id="WixMbaPrereqPackageId" Value="NetFx46Web" />
<WixVariable Id="WixMbaPrereqLicenseUrl" Value="http://go.microsoft.com/fwlink/?LinkID=558772" />
<WixVariable Id="NetFx46WebDetectCondition" Value="NETFRAMEWORK45 >= $(var.NetFx46MinRelease)" Overridable="yes" />
<WixVariable Id="NetFx46WebInstallCondition" Value="" Overridable="yes" />
<WixVariable Id="NetFx46WebPackageDirectory" Value="redist\" Overridable="yes" />
<PackageGroup Id="NetFx46Web">
<ExePackage
InstallCommand="/q /norestart /ChainingPackage "[WixBundleName]" /log "[NetFx46FullLog].html""
RepairCommand="/q /norestart /repair /ChainingPackage "[WixBundleName]" /log "[NetFx46FullLog].html""
UninstallCommand="/uninstall /q /norestart /ChainingPackage "[WixBundleName]" /log "[NetFx46FullLog].html""
PerMachine="yes"
DetectCondition="!(wix.NetFx46WebDetectCondition)"
InstallCondition="!(wix.NetFx46WebInstallCondition)"
Id="NetFx46Web"
Vital="yes"
Permanent="yes"
Protocol="netfx4"
DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=560371"
LogPathVariable="NetFx46FullLog"
Compressed="no"
Name="!(wix.NetFx46WebPackageDirectory)NDP46-KB3045557-x86-x64-AllOS-ENU.exe">
<RemotePayload
CertificatePublicKey="52868DFCA6E3AF2632389E6C1EE7D0468D3797D0"
CertificateThumbprint="3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC"
Description="Microsoft .NET Framework 4.6 Setup"
Hash="480CA134B9E3F2437DF10719D5A8C77DDEC0A4F1"
ProductName="Microsoft .NET Framework 4.6"
Size="1497400"
Version="4.6.81.0" />
</ExePackage>
</PackageGroup>
Just for the record, here's my final solution.
Right-click on the bootstrapper project References in Visual Studio and add a reference to WixUtilExtension.
Add xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" as an attribute to the top level Wix element.
Add to the <Chain> element:
<PackageGroupRef Id="vcredist_vc140"/>
Add as a child of the <Wix> element:
<Fragment>
<!-- vcredist 2015 x86 -->
<util:ProductSearch
Id="VCREDIST_140_x86"
UpgradeCode="65E5BD06-6392-3027-8C26-853107D3CF1A"
Result="version"
Variable="VCREDIST_140_x86"/>
<PackageGroup Id="vcredist_vc140">
<ExePackage
Id="vc140"
Cache="yes"
PerMachine="yes"
Permanent="yes"
Vital="yes"
Compressed="no"
DownloadUrl="http://go.microsoft.com/fwlink/?LinkID=615459"
Name="vcredist_vc140"
InstallCommand="/quiet /norestart"
DetectCondition="(VCREIST_140_x86 >= v14.0.24215)">
<RemotePayload
Description="Microsoft Visual C++ 2015 Redistributable (x86) - 14.0.24215"
ProductName="Microsoft Visual C++ 2015 Redistributable (x86) - 14.0.24215"
Size="14456872"
Version="14.0.24215.1"
Hash="72211BD2E7DFC91EA7C8FAC549C49C0543BA791B" />
</ExePackage>
</PackageGroup>
</Fragment>
UpgradeCode came from this answer and is specific to v14.0.24215 of the vcredist installer. This is how the bootstrapper decides whether it is already installed.
Compressed="no" tells the installer not to include the file in the installer itself (since we want to download it from the web).
DownloadUrl is a direct URL to the downloadable installer from this answer.
RemotePayload Description is the text of the installer's Description resource and likewise ProductName. (It appears that the text does not have to match the text in the resources. ProductName is the description shown in the bootstrapper's progress dialog.)
Size is the size in bytes.
Hash is found with the Powershell command get-filehash -algorithm SHA1 .\vc_redist.x86.exe.
I hope this helps someone.

how to manually purge an malformed wix-burn package?

I am in the process of learning how to develop a custom managed bootstrapper for wix-burn. Up to my knowlege there are no official tutorials, unofficial tutorials are always filled with WPF stuff which I'm not interested in and most people on forums do not do much more than saying that you must create a class that inherits from BootstrapperApplication and overrides the Run() method.
I did that, created the config file, added the payloads to the xml markup. The resulting installer did nothing, actually it ran forever, only killing it stopped it. I sincerely expected that calling base.Run() would give me some basic default GUI-less behavior. But that is only an abstract method. Eventually I learned that I must call some Engine.functions() to actually do some work. So I wrote this to test:
protected override void Run()
{
Engine.Detect();
Engine.Plan(LaunchAction.Install);
Engine.Apply(IntPtr.Zero);
Engine.Quit(0);
}
I successfully compiled a package that actually installed, the problem is that it can not be uninstalled. My question is, what can I do to purge it from my system? What registry keys must I erase, what cached packages must I delete, and what else must I do to get rid of it?
First, the registry key will be in one of the two locations listed below -- and it's probably the first one since the second is for 32-bit applications installed on a 64-bit OS.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninst‌​all
Second, you can use the registry key to determine where the executable is cached for uninstall, which is probably in a folder that looks like C:\ProgramData\Package Cache.
If this were an .msi installation, there's another registry key and the file is cached in a different location as mentioned here.
Other links:
https://superuser.com/questions/401511/how-to-remove-a-broken-program-from-the-programs-and-features-list-in-windows-7
https://support.microsoft.com/en-us/kb/247501
Ufff, you've got yourself into a hell. :) I'll help you as much as I can.
How did you installed that package?
dlls that you can find interesting:
BootstrapperCore.dll (included with the WiX SDK)
Microsoft.Deployment.WindowsInstaller.dll (included with the WiX SDK)
WindowsBase.dll (for threading)
And, one of XML files should be like this, so you can see what exactly is up there.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="My Test Application" Version="1.0.0.0" Manufacturer="Bryan" UpgradeCode="PUT-GUID-HERE">
<BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost">
<Payload SourceFile="..\TestBA\BootstrapperCore.config"/>
<Payload SourceFile="..\TestBA\bin\Release\TestBA.dll"/>
<Payload SourceFile="..\TestBA\bin\Release\GalaSoft.MvvmLight.WPF4.dll"/>
<Payload SourceFile="C:\Program Files\WiX Toolset v3.6\SDK\Microsoft.Deployment.WindowsInstaller.dll"/>
</BootstrapperApplicationRef>
<Chain>
<PackageGroupRef Id='Netfx4Full' />
<MsiPackage SourceFile="..\DummyInstaller\bin\Release\DummyInstaller.msi" Id="DummyInstallationPackageId" Cache="yes" Visible="no"/>
</Chain>
</Bundle>
<Fragment>
<!-- Managed bootstrapper requires .NET as a dependency, since it was written in .NET.
WiX provides a Bootstrapper for the bootstrapper. The fragment below includes .NET.
For more information or examples see Heath Stewart's blog or the WiX source:
http://blogs.msdn.com/b/heaths/archive/2011/10/28/introducing-managed-bootstrapper-applications.aspx
-->
<WixVariable Id="WixMbaPrereqPackageId" Value="Netfx4Full" />
<WixVariable Id="WixMbaPrereqLicenseUrl" Value="NetfxLicense.rtf" />
<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" />
<PackageGroup Id="Netfx4Full">
<ExePackage Id="Netfx4Full" Cache="no" Compressed="yes" PerMachine="yes" Permanent="yes" Vital="yes"
SourceFile="C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages\DotNetFX40\dotNetFx40_Full_x86_x64.exe"
DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=164193"
DetectCondition="Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)" />
</PackageGroup>
</Fragment>
</Wix>
Note: your registry search and conditions are a little different from
what is used in the WiX toolset to detect NETFX. The following is the
detection for NETFX the WiX toolset uses:
<util:RegistrySearch
Id="NETFRAMEWORK40"
Variable="NETFRAMEWORK40"
Root="HKLM"
Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"
Value="Install"
Result="value" />
Next solution can be this:
Include a PackageGroupRef element in your Chain:
<Bundle>
<Chain>
<PackageGroupRef Id="NetFx452" />
<MsiPackage ... />
</Chain>
</Bundle>
Download the Microsoft .NET Framework 4.5.2 (Offline Installer), and add it to your Bootstrapper Project. (I put it in a folder called "Resource".)
Add the following Fragment:
<Fragment>
<util:RegistrySearchRef Id="NETFRAMEWORK45"/>
<PackageGroup Id="NetFx452">
<ExePackage Id="NetFx452"
Cache="no"
Compressed="yes"
PerMachine="yes"
Permanent="yes"
Vital="yes"
Name="NDP452-KB2901907-x86-x64-AllOS-ENU.exe"
SourceFile="Resource\NDP452-KB2901907-x86-x64-AllOS-ENU.exe"
DetectCondition="NETFRAMEWORK45"
InstallCommand="/q /norestart" />
</PackageGroup>
</Fragment>

WiX - How to link an ExePackage element into a Product

I am trying to include the VC++ Redistributable 2013 prerequisites installation in my MSI installer.
I have modified the Fragment written by this guy to quietly download and install the vcredist_x86.exe package after performing a registry check (file - MyWixProject/vcredist.wixobj):
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?define vcredist_x86="http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x86.exe"?>
<Fragment>
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\DevDiv\vc\Servicing\12.0\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\vc\Servicing\12.0\RuntimeMinimum" Value="Install" Variable="vcredist" />
<PackageGroup Id="vcredist">
<PackageGroupRef Id="InstallVCRedist"/>
<ExePackage Id="vcredist_x86"
Cache="no"
Compressed="no"
PerMachine="yes"
Permanent="yes"
Vital="yes"
Name="Redist\vcredist_x86.exe"
SourceFile="Redist\vcredist_x86.exe"
DownloadUrl="$(var.vcredist_x86)"
InstallCommand="/q"
DetectCondition="vcredist AND (vcredist >= 1)">
<ExitCode Value ="3010" Behavior="forceReboot" />
</ExePackage>
</PackageGroup>
</Fragment>
</Wix>
I am trying to reference this Fragment from my Product element (file MyWixProject/Product.wxs). I read that "The contents of a Fragment element can be linked into a product by utilizing one of the many *Ref elements". But how can a ExePackage or its PackageGroupRef be referenced from the main Product element? Or is there another way to compile the .wixobj and its Fragment from within the .wxs Product?>
ExePackage works only in a Bundle, not a Product. MSI doesn't support multiple Products installing at the same time and the VC++ redistributable is just a Bundle with multiple Products in it.

WiX - Does Burn support dual-purpose msi packages?

Does Burn support dual-purpose (per-user or per-machine) MSI packages which were prepared according to these Microsoft guidelines?
I tried to prepare such a package, but it looks like bootstrapper created with Burn doesn't uninstall MSI package, which was installed per-machine after raising UAC privileges by End-User.
The source code for Burn is:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Version="1.0"
Name="AppNameHere"
UpgradeCode="GuidHere">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense" >
<bal:WixStandardBootstrapperApplication LicenseUrl=""
SuppressOptionsUI="yes"
ThemeFile="Customization\Theme.xml"
LocalizationFile="Customization\LangHere.wxl"/>
</BootstrapperApplicationRef>
<Chain>
<PackageGroupRef Id="WindowsInstaller45"/>
<PackageGroupRef Id="NetFx40ClientRedist"/> <!-- Uzywa rozszerzenia WixNetfxExtension do zainstalowania .net -->
<PackageGroupRef Id="vcredist"/>
<MsiPackage Compressed="yes"
SourceFile="MsiFileNameHere"
DisplayInternalUI="yes">
<MsiProperty Name="UPDATEDIR" Value="[UninstallPath]"/>
<MsiProperty Name="WIXBUNDLEKEY" Value="[WixBundleProviderKey]"/>
</MsiPackage>
</Chain>
</Bundle>
<Fragment>
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\10.0\VC\VCRedist\x86" Value="Installed" Variable="vcredistkeyx86" />
<util:RegistrySearch Root="HKLM" Key="SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\VC\VCRedist\x86" Value="Installed" Variable="vcredistkeyx64" />
<PackageGroup Id="vcredist">
<ExePackage Id="vcredist_x86"
Cache="no"
Compressed="yes"
PerMachine="yes"
Permanent="yes"
Vital="yes"
SourceFile="Components\vcredist_x86.exe"
DetectCondition="(vcredistkeyx86 AND (vcredistkeyx86 >= 1)) OR (vcredistkeyx64 AND (vcredistkeyx64 >= 1))" />
</PackageGroup>
<PackageGroup Id="WindowsInstaller45">
<ExePackage Cache="no"
Compressed="yes"
PerMachine="yes"
Permanent="yes"
Vital="yes"
SourceFile="Components\WindowsXP-KB942288-v3-x86.exe"
InstallCondition="VersionNT=v5.1 AND NOT VersionNT64 AND VersionMsi < v4.5"
InstallCommand="/quiet /norestart">
<ExitCode Behavior="forceReboot"/>
</ExePackage>
</PackageGroup>
</Fragment>
</Wix>
As of WIX V3.9 the answer is a qualified "No" - Burn doesn't currently support dual-purpose per-user or per-machine MSI package.
A dual-purpose MSI package has the ALLUSERS property set to "2". When you build a WIX bootstrapper project referencing this type of MSI package you should see this type of warning:
2>D:\Robert\Documents\Visual Studio 2013\Projects\BurnTest\Bootstrapper\Bundle.wxs(18,0): warning LGHT1133: Bundles require a package to be either per-machine or per-user. The MSI 'D:\Robert\Documents\Visual Studio 2013\Projects\BurnTest\SetupProject\bin\Release\SetupProject.msi' ALLUSERS Property is set to '2' which may change from per-user to per-machine at install time. The Bundle will assume the package is per-machine and will not work correctly if that changes. If possible, remove the Property with Id='ALLUSERS' and use Package/#InstallScope attribute instead.
The build process for a WIX bootstrapper project will try and work out from the chained packages what type of burn installation to create (per-user or per-machine). The logic is convoluted because of the different places you can declare a preference for per-user or per-machine, and the potential conflicts between chained packages. But the general idea is the burn compiler will generate a per-machine installation, unless one of the chained packages is per-user, which will flip the burn installation into per-user mode. The key point is the decision to create a per-user or per-machine package is made at build time. To properly support dual-purpose MSI packages that decision would need to be moved to install time.

WiX Bootstrapper doesn't start/work

Ive a problemm with my wix bootstrapper to install .Net 4 and my application(.msi generated with wix 3.7). When i compile my solution everything is ok, and the generated exe has the right size(not sure if important, when i use winrar to open the exe there are just a few files in it, and not the files i want to install).
When i double click my exe nothing happens(with and without administrator).
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="Bootstrapper" Version="1.0.0.0" Manufacturer="asdf"
UpgradeCode="{D188D758-2913-4BA8-B9BA-FEC5B4BCCBD7}">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />
<Chain>
<!-- TODO: Define the list of chained packages. -->
<PackageGroupRef Id="Netfx4Full"/>
<MsiPackage Id="Myapp" SourceFile="$(var.Myapp.TargetPath)"/>
</Chain>
</Bundle>
<Fragment>
<!-- Check for .NET 4.0 -->
<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" />
<PackageGroup Id="Netfx4Full">
<ExePackage Id="Netfx4Full"
DisplayName="Microsoft .NET Framework 4.0"
DownloadUrl="http://download.microsoft.com/download/5/6/2/562A10F9-C9F4-4313-A044-9C94E0A8FAC8/dotNetFx40_Client_x86_x64.exe"
Compressed="no"
Cache="yes"
PerMachine="yes"
Permanent="yes"
Protocol="netfx4"
Vital="yes"
SourceFile=".\dotNetFx40_Full_x86_x64.exe"
InstallCommand="/passive /norestart"
DetectCondition="Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)" />
</PackageGroup>
</Fragment>
</Wix>
Myapp.msi is imported as reference in the bootstrapper projekt.
May someone can help me where ive to look(iam not sure if im able to create a logfile)
if theres any code i should post pls let me know
Thank u very much
Have you tried including the "Compressed" attribute for your MSIPackage entry? For example:
<Chain>
<!-- TODO: Define the list of chained packages. -->
<PackageGroupRef Id="Netfx4Full"/>
<MsiPackage Id="Myapp" SourceFile="$(var.Myapp.TargetPath)" Compressed="yes" Vital="yes" />
</Chain>
The "Compressed" attribute tells Burn to include your msi in the generated bootstrapper package. The "Vital" attribute tells Burn that your msi is required.
Also, burn packages write logs to your temp. directory. So look in there if it still fails.