WIX is a great toolset for creating installers. In most of the cases when you need an installer, you need some custom logic to be executed. It's great that WIX supports managed custom actions. Anyway, it wasn't so easy for me to make it work, so I want to share my experience. I will demonstrate it using the WIX Visual Studio add-in (version v3.7.1217.0).
We will create WIX Setup project and C# Custom Action Project.
We will add a dummy text file in the setup project to be used as installation content and will change a little bit the auto created Product.wxs file.
="1.0"="UTF-8"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WixWithCustomAction"
Language="1033" Version="1.0.0.0"
Manufacturer="Trifonov"
UpgradeCode="60468a7d-6485-4e7e-bf82-503213bc43a8">
<Package InstallerVersion="200"
Compressed="yes" InstallScope="perMachine" />
<Media Id='1' Cabinet='Dummy.cab' EmbedCab='yes' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder'>
<Directory Id='WixWithCustomAction' Name='WixWithCustomAction'>
<Component Id="DummyContent"
Guid="ba9028ae-0d3b-4b66-8560-f53330736265">
<File Id="DummyFile" KeyPath="yes"
Source="Dummy.txt" Vital="yes" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Complete" Title="WixWithCustomAction" Level="1">
<ComponentRef Id='DummyContent' />
</Feature>
</Product>
</Wix>
That's how our solution looks like:
If we build the WixWithCustomAction
project, WixWithCustomAction.msi will be created. If we run it, WixWithCustomAction folder will be created in program files with Dummy.txt file inside. But now, we want to add a custom action which will create a file in C:\Temp folder. We will use the MyCustomActionProject
for this. Let's change the CustomAction
class a little bit:
using Microsoft.Deployment.WindowsInstaller;
using System.IO;
namespace MyCustomActionProject
{
public class CustomActions
{
[CustomAction]
public static ActionResult MyCustomAcion(Session session)
{
session.Log("Executing MyCustomAcion");
File.CreateText(@"c:\temp\installed.txt");
return ActionResult.Success;
}
}
}
Now, we just need to call this custom action from the installer. To do this, we will add a reference to this project in the setup project.
Now let's add the custom action in the Product.wxs file. Adding the project as a reference allows as to use these variables. But adding custom action is a little bit complicated. After building the MyCustomActionProject.dll file, we will need a call to MakeSfxCA.exe and sfxca.dll in your installed WiX toolset as the DLL needs a reference to Microsoft.Deployment.WindowsInstaller.dll and has CustomAction.config attached. Calling the MakeSfxCA.exe tool will package, the project output to MyCustomActionProject.CA.dll (here you can find some additional information about this). As we use "C# Custom Action Project" there is an import added to $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.CA.targets file which will create this package on build. To check this, you can build the custom action project and see the output:
So the custom action in the Product.wxs needs to reference the .CA.dll file. That's why we cannot use $(var.MyCustomActionProject.TargetPath)
as a source for the custom action binary, but we will have to construct the source path like this: $(var.MyCustomActionProject.TargetDir)$(var.MyCustomActionProject.TargetName).CA.dll. The other option is not to use the project reference but add the full path to the custom action output. So we will add the following rows to the wxs file:
<Binary Id='CustomActionBinary'
SourceFile='$(var.MyCustomActionProject.TargetDir)$(var.MyCustomActionProject.TargetName).CA.dll' />
<CustomAction Id='CustomActionId' BinaryKey='CustomActionBinary'
DllEntry='MyCustomActionMethod' Execute="deferred" HideTarget="yes"/>
<InstallExecuteSequence>
<Custom Action='CustomActionId' Before='InstallFinalize'/>
</InstallExecuteSequence>
And that's it. Now if we build the setup project and run the created msi installer, c:\temp\installed.txt will be created as a part of the installation process.
You can find the solution file here.