I am using the WixToolset 6.0 with Visual Studio 2022. I am trying to create an installer that installs the following files:
<ComponentGroup Id="ApplicationFiles" Directory="PROGRAM_FOLDER">
<Component Id="CustomActionPOC.Dependency.dll" Guid="{F0D4FF63-0835-4E3C-8892-719F653BEA08}">
<File Source="CustomActionPOC.Dependency.dll" KeyPath="true" />
</Component>
<Component Id="CustomActionPOC.exe" Guid="{20D68207-836C-4422-B179-E0C052FB8C7D}">
<File Source="CustomActionPOC.exe" KeyPath="true" />
</Component>
<Component Id="CustomActionPOC.exe.config" Guid="{7B48E6A4-2AAD-4663-8E47-05F6E5733FD2}">
<File Source="CustomActionPOC.exe.config" KeyPath="true" />
</Component>
</ComponentGroup>
During the installation, for each file being copied, check if it already exists on the target and do the following (assume all files have a valid version number):
- If it doesn't exist, just copy the new file
- If it does exist, check the version.
- If the installed file has a lower version, back it up and then copy the new file.
- If the versions are the same, just copy the new version
- If the installed file has a higher version, do not copy the new file and move on.
I am pretty confident I need to use a custom action to do this, so I created a CA project with one function:
[CustomAction]
public static ActionResult OnInstall(Session session)
{
session.Log("Begin OnInstall");
}
In my WXS file, I set it up to call the CA:
<Fragment Id="CustomActionProperties">
<Binary Id="CADLL" SourceFile="CustomActionPOC.CustomActions.CA.dll" />
<CustomAction Id="InstallCA" BinaryRef="CADLL" DllEntry="OnInstall" Return="check" />
</Fragment>
...
<InstallExecuteSequence>
<Custom Action="InstallCA" Before="InstallFiles" />
</InstallExecuteSequence>
Attaching to the process and setting a breakpoint in my C# method, it seems to be hitting the breakpoint, but I am not sure how to proceed from there. The session object has values, but I can't drill into the Component property to see the Files.
?session.Components
{WixToolset.Dtf.WindowsInstaller.ComponentInfoCollection}
Count: 3
Results View: Expanding the Results View will enumerate the IEnumerable
?session.Components["CustomActionPOC.Dependency.dll"]
{WixToolset.Dtf.WindowsInstaller.ComponentInfo}
CurrentState: Local
Name: "CustomActionPOC.Dependency.dll"
RequestState: Unknown
?session.Components["CustomActionPOC.Dependency.dll"]
My thought pattern is that I can use the CA to traverse all files in the installer prior to anything copying over but I hit some roadblocks:
- Is this pattern even the way to go? That is, iterating through the files in the installer and checking against the existing files? If so, how would I pull the file info from the installer so that I can do the comparison (e.g., how would I pull the version from the file in the MSI)?
- If a better pattern is needed, can you please describe it or at least point me in the right direction?
I really wish it was as simple as an attribute on the File element that would function something like this:
<File Source="CustomActionPOC.Dependency.dll" KeyPath="true" CheckExists="true" Backup="C:\MyBackups\FileA.dll" CreateBackupFolder="true" Condition="VersionLessThan" />