WiX install C++ redistributable in msi - wix

Following on from my last question Why does my WiX Custom action throw a System.IO.FileNotFoundException?, I am now trying to get the C++ distributable installed as part of my msi.
I have followed the example as per the documentation; http://wix.sourceforge.net/manual-wix3/install_vcredist.htm
<DirectoryRef Id="TARGETDIR">
<Merge Id="VC_Redist" SourceFile="$(env.ProgramFiles)\Common Files\Merge Modules\Microsoft_VC100_CRT_x86.msm" DiskId="1" Language="0"/>
</DirectoryRef>
<Feature Id="Complete" Level="1" Title="$(var.NVRProduct) $(var.NVRVersion)" Description="Everything" Display="expand">
<Feature Id="VC_Redist" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<MergeRef Id="VC_Redist"/>
</Feature>
</Feature>
It does not work. The C++ distributable is not installed, and subsequently my msi throws an error as the C++ distribution is missing, and uninstalls itself.
This seems to be the same as this question, which was not really answered.
C++ Redistributable package with WIX
Any ideas appreciated.

I am going to answer my own question as there are a number of issues I found out after further investigation.
Firstly, the install of the VC++ merged module was actually working!
I didn't think it was because I was still getting an error, and I couldn't see an entry for the VC++ runtime in the Add Remove programs like you can if you install it manually.
However, by changing the installation to only install the distributables and the application up to where I received the error, I could see the VC++ dll was actually being installed. The error I was now seeing was because the program required the ATL redistibutable as well. (As I discovered through using Dependency Walker). The error caused the msi to fail, and the VC++ dll was being uninstalled along with the rest of my application dlls!
Once I provided the VC++ and the ATL distributables using the mechanism as per the example in the help file, all was well.
I have also used the statically linked SQLite dll as even with the distributables being installed, the initial calls to SQLite from the custom action were failing. I think this must be due to an installation sequence issue. However, using the statically linked version has raised a degree of discussion among developers here, with around a 50-50 split in favour and strongly against using it.
The installation does now work, however.

Sounds like your custom action is either scheduled before the InstallFiles action or not deferred or both. You don't provide the custom action definition but make sure your CustomAction element has the Execute attribute set to 'deferred' and ensure your Custom element is in the InstallExecuteSequence scheduled After='InstallFiles'.
Alternatively, you might consider statically linking the CRT into your custom action. I always recommend this option since it makes your custom action stand alone which greatly increases the chance that the custom action will always work (including during install, repair, uninstall, and patching).

Related

WiX DLL component refuses to install

I am using Wix to install an application. The trick here is that the application is being installed on top of another, third party application.
I am installing both using a bootstrapper.
The application I am installing on top of has a DLL that we have customized in OUR application, so I need to overlay the original DLL with ours.
What is happening is that our application installer seems to be refusing to install the DLL. The log shows this in the InstallValidate step:
Component: DotEditPanels.dll; Installed: Absent; Request: Local; Action: Null
I have tried all sorts of things to make this happen. I started with using A tag in the Component to delete the original DLL, followed by a to install it.
The component is getting skipped, as you see above.
I then went to using a Custom Action to delete the original DLL, which works fine, with just the in the Component. Same thing.
Trying a few more things, the Component currently looks like this:
<Component Id="DotEditPanels.dll" Guid="*" NeverOverwrite="no" SharedDllRefCount="yes">
<File Id="filF8E7A8CEDC214A73A82277F1BA3B677F" KeyPath="yes" Source="..\..\DotEditPanels-8.1-FP2\bin\$(var.Configuration)\DotEditPanels.dll" />
</Component>
All I need is for this new DLL to get laid down, and I can't seem to make the installer do it. Any ideas?
File overwrite rules are based on file versions, so if your file version is less than that of the installed file, that's the obvious explanation. This rule is the basis of patches, hot fixes, service packs and so on, so if your version control is doing it's job that existing version should be newer than yours. The assumption is also that Dlls like that are compatible with older apps that may already be installed.
Anyway, you mention an assembly, so if it's managed code then you can set AssemblyFileVersion to a version that will overwrite the existing Dll. Otherwise it defaults to the assembly version. If you need to keep the assembly version the same because clients are bound to it they will still be ok, then use file version to denote later versions and overwrite older versions.
I figured as much.
So, I actually "cheated". I added the DLL as a Binary object, then used a custom action to delete the original DLL and read the new DLL from the Binary object in the installer database and write it to the proper place.
Yes, I know it's probably not "kosher", but it is getting the job done for my purposes.

Running regsvr32 as part of a WIX installer

I have authored a COM component that is distributed through a WIX-generated MSI.
The COM component has rather complicated and non-static registration logic which means that embedding the registration information directly in the Windows Installer WXS file is not a feasible option - registration must be done using regsvr32 - and it's a 32-bit COM component, so it must use the 32-bit version of regsvr32.exe - that is %SystemRoot%\SysWow64\regsvr32.exe on 64-bit Windows or %SystemRoot%\System32\regsvr32.exe on x86 Windows.
I noticed two problems with WIX with this WXS XML:
<InstallExecuteSequence>
<Custom Action="COMRegister" After="InstallFinalize">NOT Installed</Custom>
<Custom Action="COMUnregister" After="InstallInitialize">Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="COMRegister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s "[APPLICATIONROOTDIRECTORY]Component.dll"' />
<CustomAction Id="COMUnregister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s /u "[APPLICATIONROOTDIRECTORY]Component.dll"' />
The wrong regsvr32.exe was being invoked. I noticed that the x64 version of resgvr32.exe was being run on 64-bit systems instead of the 32-bit version.
regsvr32.exe was being run without elevated permissions, so COM registration failed with E_ACCESSDENIED.
For 1. it works if I hardcoded the path to the regsvr32.exe executable using [WindowsFolder]\SysWOW64\regsvr32.exe, but this wouldn't work on a real 32-bit machine where SysWow64 doesn't exist.
For 2. I read online that changing After="InstallFinalize" toAfter="RemoveExistingProducts"would cause it to run with elevated permissions, however instead this just gives me errors aboutRemoveExistingProducts` being an unresolved symbol name.
How can I resolve these two issues?
Update
(After struggling with this problem for the past 2 hours, I'm convinced the authors of WIX are close relations of H.P. Lovecraft)
I've worked-around the first issue by writing my own intermediate-step program which is a 32-bit executable, so it will always run under a WOW context, so it will reliably invoke the 32-bit regsvr32.exe program.
I found out the issue with the second issue was these things: For a CustomAction to run with elevated permissions (well, in the same security context as the main installer job) these conditions must be true:
<Custom/>" must haveBefore="InstallFinalize", and **not**After=""any other values forBefore=""` won't work reliably as WIX or Windows Installer might rearrange the actions (wut).
<CustomAction /> have have these attributes explicitly set:
Execute="deferred"
Impersonate="off"
Even-so, I would like to not have to use my helper program to correctly resolve the 32-bit regsvr32.exe. What options are there?
I wouldn't advise using self registration at all it is not the really the right way to do it with Windows Installer, if you really must set File/#SelfRegCost to 1.
A much better way is to extract the registry values and write them with WiX - you can also use heat to generate the values.
This sounds like something that will cause you lots of problems later. Though it sounds like you are determined to use this self-registration, please read this whole post: Self-Registration considered harmful.
Software that is doing "odd things" during self-registration are really frowned upon when found in application packaging in larger companies. Sometimes it is reason enough to throw out the entire software.
If you have stuff you need done with admin rights before your application can run, you should do it as part of the installer, but not via self-registration (see a plethora of reasons in the linked post above). It is better almost any other way, including having your main application.exe run with a command line from a custom action to trigger the custom registration steps, and then provide a good log of what has actually been done. And you should revert to normal COM registration and extraction for the COM servers.
It would be interesting to hear what is unique about your COM servers? Is it the usual licensing issue?

WiX: Use Burn to recache broken MSI

We have a busted MSI in production that needs to be fixed via msiexec /fv package.msi before it can be properly upgraded.
I was hopeful that we could wrap this procedure in Burn but this Q and response from Rob appears that it might not be possible.
I tried:
<Chain>
<MsiPackage SourceFile="fixed-package.msi">
<MsiProperty Name="REINSTALLMODE" Value="v"/>
</MsiPackage>
</Chain>
But nothing happened.
I only need REINSTALLMODE=v and not REINSTALLMODE=amus as mentioned in the linked question, so I'm not sure if that makes a difference. The broken package has bad conditions that prevents uninstall and upgrades and this new one fixes that.
Have things changed in Burn since May '13 that recaching an existing MSI is now possible?
Thanks
You can also do it with a custom action. Just have the MSI extracted as temporary file in the beginning of the install for the new version, then execute a custom action to recache it, after which continue the installation. This is how I have done it so far.
However, I don't know if Wix has support for temporary files like Advanced Installer does (which is our tool), so you might need to build a custom action for that too.

How to deploy 64-bit and a 32-bit Windows Installer package as a single setup?

I need to deploy a software setup targeting both, Windows 64bit and 32bit. I have two separate Windows Installer databases (created with WiX) for each platform, and I am using dotNetInstaller to combine both into a single installation bootstrapper executable.
I'm currently using version 1.10 of dotNetInstaller and set auto_close_if_installed=True, because I want to comletely hide the bootstrapper from the user. Still, dotNetInstaller insists on displaying a sill progress bar window while my installer is running, and doesn't really auto-close. The user needs to confirm a dialog box telling him that the application was successfully installed. But the real deal-breaker is that it doesn't support Windows 8 (yet).
Upgrading to a later version of dotNetInstaller seems to break auto_close_if_installed, so it's even worse.
So my question is: what is the current state of the art to deploy both setups in a single executable. Would Wix Burn be an option?
I know that in an ideal world, I simply provide my customers with separate installers for either platform. But they happen to be completely unaware of such subtleties, most of them don't even know what platform they are using.
I would definitely use Burn in this scenario. Something akin to the following:
<Wix>
<Bundle...>
<BootstrapperApplicationRef Id='WixStandardBootstrapperApplication.HyperlinkLicense' />
<Chain>
<MsiPackage InstallCondition='NOT VersionNT64' SourceFile='path\to\x86.msi' />
<MsiPackage InstallCondition='VersionNT64' SourceFile='path\to\x64.msi' />
</Chain>
</Bundle>
</Wix>
This is exactly one of the scenarios Burn was designed to handle.
You can do it in a single Wix via Conditions and Features.
<Feature Id='X86' Level='1'>
<ComponentRef Id='X86Feature1' />
<Condition Level="1">NOT VersionNT64</Condition>
</Feature>

Bundling Apple's Windows Bonjour installer into our msi

I've been asked to bundle Apple's Bonjour installer into our own msi installer, so that Bonjour automatically gets installed alongside our software. Anyone done this before? It doesn't seem to be trivial, as an msi installer cannot include and kick off another one. I assume I'd need some kind of batch file to run the two installers sequentially?
You'll need to use a bootstrapper to chain the Bonjour install with your installer. If you are using WiX 3.6 or later, using Burn to create a package bundle is a good option.
I found the Bonjour installer by downloading the Bonjour SDK and opening it in 7-zip, though I'm sure installing the SDK would provide access to it as well.
The way I typically like to do this is to add a new source file to your setup project for each dependency package to keep that logic separate from the main application setup.
The Bonjour package can be listed as a remote payload to retrieve on the fly, or build it into your setup. In this case, it seems more likely to build it in (Compressed="yes"). If you need to add any extra dependencies related to bonjour or parameters to pass into it, you could define them here as well.
<Fragment>
<!-- if a web link actually exists, I didn't find it... -->
<?define BonjourWebLink = "http://path/to/Bonjour.msi"?>
<PackageGroup Id="BonjourWeb">
<MsiPackage Id="BonjourWeb"
Compressed="no"
DownloadUrl="$(var.BonjourWebLink)">
</MsiPackage>
</PackageGroup>
<PackageGroup Id="Bonjour">
<MsiPackage Id="Bonjour"
Compressed="yes"
SourceFile="path\to\Bonjour.msi"/>
</PackageGroup>
</Fragment>
In your main bundle you just need to add a reference to the correct package group.
<Chain>
<PackageGroupRef Id="Bonjour"/>
<MsiPackage SourceFile="path\to\YourProduct.msi"/>
</Chain>
Since Bonjour uses MSI instead of an executable, you don't need to do anything to detect whether it is present or not; Burn will handle that for you. Actually, since WiX harvests most of the information your bundle needs from the MSI, this might be overkill, and you could just put in the MsiPackage element in your chain directly.
Don't forget to carefully check Apple's terms for doing this.
This would be a bit more work, and is prone to issues with upgrading, but you can take the Bonjour MSI and decompile it using dark. Convert the decompiled MSI into a Merge module that can be included with your installer, and you will have a single install. I have done this with some driver installs in the past, and it is usually not that complicated.
You need a bootstrapper; there are several freely available out there, including one being developed in WiX called Burn.
Wix Burn is relatively stable now.I`m using Wix 3.8.
If you are allowed to redistribute Bonjour Installer,you can chain the installer in Wix Burn. You can even put a condition to specify Bonjour as prerequesite for your installer.If it is not present,then Bonjour will be deployed, else it can be skipped.
You can check this link for understanding Burn.
http://wixtoolset.org/documentation/manual/v3/bundle/