I’ve struggled through building a new WiX installer, and I’m really happy with it, except that I also need to install a device driver.
Ideally, I’d like to be able to detect the presence of this driver by using RegistrySearch, e.g.
<Property Id="DRIVERINSTALLED">
<RegistrySearch Id="DriverInstalledSearch" Root="HKLM" Key="SOFTWARE\DriverCompany\Settings" Name="InstallPath" Type="raw" />
</Property>
If there is a value for the InstallPath registry key, then I’d like to move ahead with the device driver installation. I haven’t figured that part out yet, but that is secondary right now, because I can’t even get the device driver to install every time.
There are various examples floating around on the web, and the one corresponding to WiX v3.5 seems to follow this pattern:
<CustomAction Id="InstallDeviceDrivers" Execute="deferred" Directory="INSTALLLOCATION" ExeCommand="setup.exe" Return="check" />
.
.
.
<InstallExecuteSequence>
<Custom Action="InstallDeviceDrivers" After="InstallFiles" />
</InstallExecuteSequence>
Whenever I run my msi, I get the error “a program required for this install to complete could not be run”.
setup.exe is copied to my INSTALLLOCATION, and I have verified this by looking in that folder when my msi fails.
I played with the value of the After attribute, but InstallFiles seems to be the right one since it maintains elevated user privileges. I had originally tried InstallFinalize, but that failed and I figured that it wasn’t running with elevated privileges. The problem is, none of the other Actions I have tried work.
I then ran my installer with msiexec /i installer.msi /l*v install.log and looked over the output file. That’s where I saw a slightly more specific error:
MSI (s) (74:CC) [14:06:10:098]: Executing op: ActionStart(Name=InstallDeviceDrivers,,)
Action 14:06:10: InstallDeviceDrivers.
MSI (s) (74:CC) [14:06:10:098]: Executing op: CustomActionSchedule(Action=InstallDeviceDrivers,ActionType=1058,Source=C:\Program Files\MyCompany\MyProduct\,Target=setup.exe,)
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 1721 2: InstallDeviceDrivers 3: C:\Program Files\MyCompany\MyProduct\ 4: setup.exe
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 2205 2: 3: Error
MSI (s) (74:CC) [14:06:10:108]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1721
Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: InstallDeviceDrivers, location: C:\Program Files\MyCompany\MyProduct\, command: setup.exe
MSI (s) (74:CC) [14:06:11:800]: Note: 1: 2205 2: 3: Error
MSI (s) (74:CC) [14:06:11:800]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709
MSI (s) (74:CC) [14:06:11:800]: Product: Installer -- Error 1721. There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. Action: InstallDeviceDrivers, location: C:\Program Files\MyCompany\MyProduct\, command: setup.exe
Based off of some searching, it sounded like I just needed to run as admin, but my installer already triggers UAC… and sure enough, running the installer from an elevated command prompt didn’t help.
Can anyone recommend a next course of action for me to debug this? If you additionally have information on how to conditionally install based on the presence of a registry key, that would be really great, too. Thank you!
EDIT — I have run my installer on Windows XP 32bit and Windows 7 32bit, and it fails on both. Yet another reason to believe it’s not permissions-related.
EDIT #2 — I don’t know why I didn’t try this before, but I changed from setup.exe to notepad.exe, and Notepad launched. So obviously the CustomAction works. I’ll try again with Process Monitor to see where it’s looking for setup.exe… or perhaps I just can’t run an installer from within another installer?
I’d like to revise my answer to cover what I have learned that is relevant to what I think is a typical scenario:
First things first:
Skeleton WXS
Each of the sections below only have the information directly related to themselves. At the very end of the answer, I will post a skeleton (partially complete) .wxs.
Detecting the .NET Framework 4.0
First, you’ll need to add a project reference to WixNetFxExtension. Then add this XML to your
<Product>node: (search .chm for “.NET”)Customizing the Bitmaps
Found in Customizing Build-in WixUI Dialog Sets in the .chm. I only changed the following:
Just set them under the
<Product>element:I just create a Bitmaps folder in my WiX installer project in Visual Studio 2010.
Skipping the EULA Dialog & Setting the Installation Location
There are several built-in ways to define your installer’s look and flow, but for those of us that are lazy, you’ll only care about
WIXUI_MINIMALandWIXUI_INSTALLDIR. The former is only for the extremely lazy (this is what I originally sent to people!), but it doesn’t allow the user to do anything but click Yes to install the program. It won’t tell you that the installation is complete, either.WIXUI_INSTALLDIRstrikes a nice balance, IMO. You get the typical welcome dialog, click Next through more typical dialogs, and get a Finish button at the end of the process.Add a project reference to WixUIExtension, then use the following XML:
WiX installer guidance (Stack Overflow)
1
1
Installing Device Driver at the End
If you want to install a device driver at the end of your installation, I think the easiest way is to just ensure that the driver’s setup.exe is copied to your installation location and then executed from there. At least, that’s what I did. Then you just need to use a
CustomAction:How To: Run the Installed Application After Setup (WiX on SourceForge)
But what if you want to allow the user to decide whether or not to install the driver? Then you do this:
and your
<UI>node will now look like this:The logic added above just checks to see if the checkbox is checked, and the “and NOT Installed” is there to ensure that this operation only runs when the installer is installing your application, not uninstalling.
Using a Registry Key to Control Availability of the Checkbox
Just add the following XML to
Product:and then use
<SetProperty>instead of<Property>, as previously shown:How do I create a conditional property in WiX? (Almost like an If-Then)
Merge Module
Finally, what if you need to add the VC++ 2010 Redistributable package? I wasn’t sure of the best way to do this, and although my application worked when I did this (where it didn’t before), I found it strange that Add/Remove Programs didn’t mention anything about it actually being installed. So for this part, YMMV.
Since I run a continuous integration (CI) server that doesn’t necessarily have Visual Studio 2010 installed, I put the merge module file into my WiX installer project. I made a folder called MergeModules and put it there. The file is located in Program Files\Common Files\Merge Modules, and is called Microsoft_VC100_CRT_x86.msm. Now put the following line in your
<Directory>node:How To: Install the Visual C++ Redistributable with your installer (WiX on SourceForge)
and the following line in your
<Feature>node:Skeleton WXS
I’m providing an incomplete skeleton .wxs below. It’s incomplete because I’m only providing the element names for the stuff that isn’t directly associated with this post. The missing information is easy to find.