WIX Conditional Message on Exit - wix

I have a WIX installer which I need to also install the VC++ 2015 runtime executable. I'm using the vcredist_x64.exe as opposed to the merge modules (see this thread). I can successfully launch the vcredist_x64.exe after my msi finishes installing my application by using a custom action... however, what I'd like to do is first check to see if the runtime files already exist. If they do, then I'll just finish without running the vcredist_x64.exe. Otherwise, I'll run the custom action to install the runtimes as well.
It took some digging, but I was able to find out that the 2015 runtimes have a registry key shown below:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64
with an Installed value of 1 if they exist.
So, in my .wxs file I have the following registry search:
<!-- Visual C++ 2015 x64 -->
<Property Id="VCREDISTRUNTIMES2015INSTALLED">
<RegistrySearch Id="VCREDISTRUNTIMES2015SEARCH" Root="HKLM" Key="SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" Name="Installed" Type="raw" />
</Property>
Now, what I'd like to do is show a message on my exit dialog which says that if the runtimes aren't detected, then it will launch an installer to install them upon exit. Something like this:
<Property Id="WIXUI_EXITDIALOGOPTIONALTEXT" Value="Visual C++ Redistributable for Visual Studio 2015 is Required. Installation will proceed on exit.">
<Condition>VCREDISTRUNTIMES2015INSTALLED</Condition>
</Property>
However, this doesn't work. I get an error on the conditional tag and the project wont build. Assuming my registry search is setup correctly, can someone tell me how to properly add a conditional message on my exit dialog? Thanks!

Answering my own question... but here goes. It turns out that my registry search was just fine... but I needed to use "SetProperty" instead. So, something like this:
<SetProperty Id="WIXUI_EXITDIALOGOPTIONALTEXT" After="AppSearch" Value="The Visual C++ Redistributable Package for Visual Studio 2015 is Required. Installation will now install run-time components that are required to run C++ applications built using Visual Studio 2015.">
NOT VCREDISTRUNTIMES2015INSTALLED
</SetProperty>
Now, if the VCREDISTRUNTIMES2015INSTALLED is null (or false) then it will show the message on the exit dialog. Otherwise, there will be no message shown. Hope that helps.

Related

Wix RegistrySearch

I have installed wix as a plugin in Visual studio. I am trying to search for if MATLAB Version 9.2 exists on the PC then allow installation or else abort. To achieve this I do like this
<Property Id="MATLABRUNTIMEEXISTS">
<RegistrySearch Id="Matlab_runtime_search"
Root="HKLM"
Key="SOFTWARE\MathWorks\MATLAB Runtime\9.2"
Name =" MATLABROOT"
Win64="yes"
Type="raw"/>
</Property>
<Condition Message="This application requires RUNTIME 9.2. Please install the Matlab runtime 9.2 then run this installer again.">
<![CDATA[Installed OR MATLABRUNTIMEEXISTS]]>
</Condition>
It works fine, and installer is halted when there is no MATLAB on PC. But even after installing MATLAB it stops the installer.
The MATLABROOT key is "REG_SZ" and "C:\Program Files\MATLAB\MATLAB Runtime".
So what I want to test is actually only the presence of MATLABROOT key.
I saw in other questions people are using <util:RegistrySearch>, but I am not able to use that. I receive error "unsupported extension element", even though I have UtilExtension as reference already added.
Could anyone suggest me what I need to do to actually make it work?

Wix per user installer to detect the Visual C++ 2015 Redistributable

I am creating an .msi installer which has to determine whether the Visual C++ 2015 Redistributable is present in the system and if not then interrupt the installation with custom message. The official Wix documentation refers to the actual installation of the VC++ which I do not wish to do as my installer is "per user" , There are couple of others stackoverflow questions which refer to the bundle rather than the .msi http://wixtoolset.org/documentation/manual/v3/howtos/redistributables_and_install_checks/install_vcredist.html.
Wix Burn vcredist, WIX check if VS2015 C++ redistributable is installed , https://gist.github.com/nathancorvussolis/6852ba282647aeb0c5c00e742e28eb48
So I guess the question is, how to efficiently detect the presense of Visual C++ 2015 Redistributable in the per user installer.
The latest supported Visual C++ downloads
Runtime Detection Approaches
I can find a few ways to detect the presence of the Visual C++ Runtime.
Registry
Keys used by the VCRedist installer (see section below)
Keys mentioned in my original answer - grabbed from this old answer
File Presence & Version Check
Check for presence of core runtime files
See separate section below
MSI API
You can detect whether a specific MSI is installed by looking up the product GUID
Reliable, but hard to keep track of all product GUIDs (different versions)
UPDATE: You can also use the upgrade code as described below. It should remain stable across releases and updates (for each major version and potentially between major versions as well).
Fall-Over EXE?
Suggestions are seen to use an EXE depending on the runtime
Launching it and failing means the runtime is not there or broken
Good & Bad - Evaluation: Option 1 seems to be vulnerable since the merge module variant of deploying the runtime might not write these keys. Option 3 might work well, but it is hard to keep track of all GUIDs. Option 4 seems to already have failed based on the newer runtimes removing certain registry keys. Though fixed now, this could resurface.
File Version Presence / Version Check
The more I look at this, the more I start to think that you have to check for the actual files themselves, and potentially for the right file version. The file vcruntime140.dll in the System32 folder (64-bit version) and SysWOW64 folder (32-bit version)? See files list towards bottom here.
Just adding a link for safe-keeping.
How to detect the presence of the Visual C++ 2012 redistributable package?
Redistributing Visual C++ Files
A test VBScript - for test purposes only (scripts are sometimes blocked by anti-virus):
Set fso = CreateObject("Scripting.FileSystemObject")
MsgBox fso.GetFileVersion("C:\Windows\System32\vcruntime140.dll")
You can detect file presence and version using AppSearch in an MSI file.
Below are some other stuff I wrote up, just leaving it in.
VCRedist
It seems the Visual C++ Redistributable Packages (VCRedist_x86.exe, VCRedist_x64.exe) - which is the recommende way to deploy the runtime - checks the following registry key to determine what versions of the runtime is actually installed:
HKLM\SOFTWARE\Microsoft\VisualStudio\<version>\VC\Runtimes\
The sub-keys x86 and x64 seem to all contain an "Installed" value that is set to 1 when the runtime is installed. I would assume - without having had time to test it all - that you then can check:
HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64 Installed = 1
HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x86 Installed = 1
Merge Module: After a brief check, it looks like these values are not written by the merge modules that can also be used to distribute this runtime. I do not have the time or means to check this properly now.
Astonishingly both version 2015 and version 2017 of the runtime write to the 14.0 key - since they are binary compatible. If the 2017 version is installed, then the VCRedist executable will return an error since no install is needed. Weird indeed. But for your purpose that should be besides the point. Source.
MSI API - Retrieve Product Codes
Mailbag: How to detect the presence of the VC 8.0 runtime redistributable package
Updated VC 8.0 runtime redistributable packages are included in Visual Studio 2005 SP1
How can I find the product GUID of an installed MSI setup?
UPDATE: installer.ProductState - normal installed state is 5:
I forgot about the ProductState property when writing the below.
You can check for an installed product with two lines of code if you
have the actual product code:
Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
MsgBox installer.ProductState("{00000000-0000-0000-0000-000000000001}")
Here is even one more way to do it: MSDN: How to programmatically check for the presence of a Windows Installer-based product by using its product code.
Tip: I wouldn't use this approach seeing as the product code changes frequently when products are updated. Hence I like better to
check for file versions of core-runtime files. This seems more
reliable for the future (provided version parsing is done correctly
and reliably - don't roll your own).
Mockup:
Public installer
Set installer = CreateObject("WindowsInstaller.Installer")
' Don't have the 2015 GUID
VC2015 = CheckForProductCode("{00000000-0000-0000-0000-000000000000}")
VC2017 = CheckForProductCode("{C77195A4-CEB8-38EE-BDD6-C46CB459EF6E}")
MsgBox "VC2015: " & CStr(VC2015) & vbCrLf & "VC2017: " & CStr(VC2017)
Function CheckForProductCode(productcode)
CheckForProductCode = False
For Each product In installer.ProductsEx("", "", 7)
If(LCase(productcode) = LCase(product.ProductCode)) Then
CheckForProductCode = True
Exit For
End If
Next
End Function
Update based on Zett42's suggestion to enumerate products sharing the same upgrade code:
Set installer = CreateObject("WindowsInstaller.Installer")
' Enumerate all products related to "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148"
' {AA783A14-A7A3-3D33-95F0-9A351D530011} is the upgrade code
Set upgrades = installer.RelatedProducts("{AA783A14-A7A3-3D33-95F0-9A351D530011}")
For Each u In upgrades
MsgBox u, vbOKOnly, "Product Code: "
Next
Deploying The Visual Studio C++ Runtime
Beyond detection, there are several approaches for distributing the Visual Studio C++ Runtime:
Static Linking
Visual C++ Redistributable Packages
VCRedist_x86.exe, VCRedist_x64.exe, or VCRedist_arm.exe
Program Files(x86)\Microsoft Visual Studio\2017\edition\VC\Redist\MSVC\lib-version
Redistributable Merge Modules (.msm files)
Insufficient for some purposes (The universal CRT):
Redistributables for deploying C++ exe developed with Visual Studio 2015 on Windows 7
WIX merge c++ runtime
Local Application Folder
Copy DLLs to the local application folder
Not recommended for servicing reasons (updates, security fixes)
Links For Safe Keeping:
Redistributables for deploying C++ exe developed with Visual Studio 2015 on Windows 7
How to detect whether I need to install VCRedist?
WIX merge c++ runtime
How to detect if Visual C++ 2017 Redistributable is installed
Old Answer
There is this old post. I am not too fond of direct registry reads, let me see if I can find a more reliable way, but maybe have a look in the mean time: Detect if Visual C++ Redistributable for Visual Studio 2012 is installed
Just one more link, how to find the Windows Installer product code of products that are installed: How can I find the product GUID of an installed MSI setup?
You can use LaunchConditions from WiX Toolset. The detection can be done by RegistrySearch.
Until version 2015 it was just a registry key, GUID value. Since 2017 and still in 2019 the key is concat (merged), so it is not that easy anymore. This is way I used a loop from 21 to 40 to find all places. C++ Runtime Documentation.
Add the following lines to your product.wxs inside the Product elemnent:
...
<!-- Visual C++ Redistributable 2015, 2017 and 2019 (x86) -->
<Property Id="CPPRUNTIME2015X86" Secure="yes">
<!-- C++ 2015 -->
<RegistrySearch Id="mfc140x86_23026" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{74d0e5db-b326-4dae-a6b2-445b9de1836e}" Type="raw" />
<RegistrySearch Id="mfc140x86_24215" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{e2803110-78b3-4664-a479-3611a381656a}" Type="raw" />
<!-- C++ 2017 -->
<RegistrySearch Id="mfc1416x86" Root="HKCR" Key="Installer\Dependencies\VC,redist.x86,x86,14.16,bundle" Type="raw" />
<!-- C++ 2019 -->
<?foreach CPPRUNTIMEVERSIONPREFIX in 21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40?>
<RegistrySearch Id="mfc14$(var.CPPRUNTIMEVERSIONPREFIX)x86" Root="HKCR" Key="Installer\Dependencies\VC,redist.x86,x86,14.$(var.CPPRUNTIMEVERSIONPREFIX),bundle" Type="raw" />
<?endforeach ?>
</Property>
<Condition Message="Microsoft Visual C++ 2015-2019 (x86) Redistributable missing">
<![CDATA[((REMOVE="ALL")) OR Installed]]>
</Condition>
<!-- Visual C++ Redistributable 2015, 2017 and 2019 (x64) -->
<?if $(var.Platform) = x64 ?>
<Property Id="CPPRUNTIME2015X64" Secure="yes">
<!-- C++ 2015 -->
<RegistrySearch Id="mfc140x64_23026" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{e46eca4f-393b-40df-9f49-076faf788d83}" Type="raw" />
<RegistrySearch Id="mfc140x64_24215" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{d992c12e-cab2-426f-bde3-fb8c53950b0d}" Type="raw" />
<!-- C++ 2017 -->
<RegistrySearch Id="mfc1416x64" Root="HKCR" Key="Installer\Dependencies\VC,redist.x64,amd64,14.16,bundle" Type="raw" />
<!-- C++ 2019 -->
<?foreach CPPRUNTIMEVERSIONPREFIX in 21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40?>
<RegistrySearch Id="mfc14$(var.CPPRUNTIMEVERSIONPREFIX)x64" Root="HKCR" Key="Installer\Dependencies\VC,redist.x64,amd64,14.$(var.CPPRUNTIMEVERSIONPREFIX),bundle" Type="raw" />
<?endforeach ?>
</Property>
<Condition Message="Microsoft Visual C++ 2015-2019 (x64) Redistributable missing">
<![CDATA[((REMOVE="ALL")) OR Installed]]>
</Condition>
<?endif ?>
...

Working sample for installing a VSIX extension for VS2017 using WixToolset?

I'm trying to install a VSIX Extension into Visual Studio 2017 from a Setup created with the WIX Toolset.
I found this page:
http://wixtoolset.org/development/wips/5433-add-support-to-detect-and-install-vsix-packages-into-vs15/
But its not fully clear whether the "proposals" on that page were really implemented. I did a number of experiments, with no success.
Have the features posposed on the above page been implemented in WiX v3.11.1?
There seems to be some support for VS2017 in WIX v3.11.1, but when I use the VSExtension:VsixPackage element in my Product.wxs file, it seems that the latest VSIXInstaller.exe (of my VS2017 community) isn't found and my Setup Fails.
Can someone provide a working example for this?
Thanks!
I can only tell you my strategy for IsWiX:
https://github.com/iswix-llc/iswix
iswix/Source/Application/IsWiXNewAddIn/
iswix/Source/Installer/IsWiXNewAddInMM/
iswix/Source/Installer/IsWiX/Code/Product.wxs
I'm able to install to VS2013-2017 this way.
What is IsWiX?
https://github.com/iswix-llc/iswix-tutorials
PS- 60 min complimentary dev to dev screenshares are available.
Installing extensions in Visual Studio versions newer than 2015 is not supported by WiX, despite it being able to detect VS 2017 and VS 2019 instances … which is kind of odd to be honest.
There is still the option of using the detected installations to launch the installer, though that might break unexpectedly.
You can try this:
Add WiX VSExtension (obviously):
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:VSExtension="http://schemas.microsoft.com/wix/VSExtension">
Define and set a property containing the VSIX Installer location (done here for Visual Studio 2019):
<Property Id="Vs16VsixInstaller" Value="0" />
<SetProperty Action="SetVs16VsixInstaller" Id="Vs16VsixInstaller" Value="[VS2019_IDE_DIR]VSIXInstaller.exe" Sequence="both" After="AppSearch" />
Define a component containing the extension:
<Component Id="MyVSExtension" Directory="VisualStudioExtensionsFolder" Guid="PUT-GUID-HERE">
<RegistryValue KeyPath="yes" Root="HKMU" Key="Software\[Manufacturer]\[ProductName]" Name="MyVSExtensionInstalled" Type="string" Value="" />
<VSExtension:VsixPackage File="MyVSExtension.vsix" PackageId="PUT-PACKAGE-ID-HERE" VsixInstallerPathProperty="Vs16VsixInstaller" />
</Component>
This worked in my case and I don't think there is a much better way of doing this while also keeping the solution simple.

How to bundle 6 msi into one msi installer

I have 6 msi that I want to bundle into single msi package. These 6 are office addin, out of these 3 are for office 2003 and 3 for office 2007. So my single msi should install only 3 addon based on the version of office. And there are some prerequisites that i want to install before these msi.
I tried using wix for once it created a setup but after sometime same project gave error: "Error 1 Unresolved reference to symbol 'ChainPackageGroup:wwwwww' in section 'Bundle:wixB2'" .
Setup creted by wix was able to install the setups but was not able to uninstall them, may be uninstallation needed admin rights but i was not able to give.
I also tried dotnetinstaller but i could not find how to add launch condition for my 6 installers. (Inatllcheck in dotnetinstaller only checks existense of the product getting install not the launch condition) If anybody can tell me how to add launch condition like if office 2007 present then install else do not, I will be able to complete my project if somebody help me to add launch condition.
So can you please tell me what should I do to create a single installer?
I Am also new to Wix. If You post your code It will be Helpful to solve your problem. You can go through following approach it might help you.
Considering user have office 2007 installed on his system your installer should install only Add-Ins for 2007. and as you have executables for add-ins Bootstrapper is best approach for it.
For Conditional installation you first need to find which version of office is already installed.
This you can do using Registry Search
<util:RegistrySearch Id ="Office2007" Root="HKLM" Key="SOFTWARE\Microsoft\Office\12.0\Word\InstallRoot::Path"/>
This will search in specific path.
Now for Installation
<ExePackage Id="2007Addin" SourceFile="your addin path"
InstallCondition="(Office2007)"/>
There are many other useful arguments also. go through them.
Sample Program
<?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="WordAddin" Version="1.0.0.0" Manufacturer="NSS" UpgradeCode="51d04319-a135-487c-a4bb-aed77417bda7">
<BootstrapperApplicationRefId="WixStandardBootstrapperApplication.RtfLicense" />
<util:RegistrySearchRef Id ='Office2007'/>
<--Here Install condition parameter checks if specific key is found if found installs packege -->
<--You can use NOT Office2007found this will install only if registry key not found-->
<Chain>
<MsiPackage Id ="officeAddin" Compressed='yes' Cache='yes' Name='office addin' SourceFile='officeadd.msi' InstallCondition='Office2007found' DisplayInternalUI='yes'/>
</Chain>
</Bundle>
<!--Registry Search to find Which Office Version Is installed (incase registry search failed change keys according)-->
<Fragment>
<util:RegistrySearch Id="office2007" Root="HKLM" Key="SOFTWARE\Microsoft\Office\12.0" Value="Version" Variable="Office2007found"/>
<--Below condition is only to check whether registry search is successful or not. remove it if not required-->
<bal:Condition Message="Failed to search regKey">Office2007found</bal:Condition>
</Fragment>
</Wix>
For Your Reference
wix installer 3.7 bootstrapper Registry search
How to detect installed version of MS-Office?
http://www.c-sharpcorner.com/UploadFile/cb88b2/installing-prerequisites-using-wix-bootstrapper-project-and/
Launch Condition to Detect Office 2010 Applications

WiX install C++ redistributable in msi

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).