The following is a setup using a customized Wix configuration file to automatically close and terminate running app exe files upon removal.
Here, we'll use a project from GitHub as an example.
- open https://github.com/life888888/JPdfBookmarks_INSTALLER_BUILD
- `<Code> -> Download ZIP`
- unzip JPdfBookmarks_INSTALLER_BUILD-main.zip
Project Tree
```bash
JPdfBookmarks_INSTALLER_BUILD-main/src
├── build-installer-msi-pre-setup-JDK.bat
├── build-installer-msi-pre-setup-WiX.bat
├── build-installer-msi-3.0.2.bat
....
└── windowsOverride
└── main.wxs
```
## main.wxs Original Version
`main.wxs` is a custom file I created to add the directory where the app is located to the `PATH` environment variable after installation. This way, I can directly run my app exe from any other directory.
```xml
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?ifdef JpIsSystemWide ?>
<?define JpInstallScope="perMachine"?>
<?else?>
<?define JpInstallScope="perUser"?>
<?endif?>
<?define JpProductLanguage=1033 ?>
<?define JpInstallerVersion=200 ?>
<?define JpCompressedMsi=yes ?>
<?ifdef JpAllowUpgrades ?>
<?define JpUpgradeVersionOnlyDetectUpgrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectUpgrade="yes"?>
<?endif?>
<?ifdef JpAllowDowngrades ?>
<?define JpUpgradeVersionOnlyDetectDowngrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
<?endif?>
<?include $(var.JpConfigDir)/overrides.wxi ?>
<Product
Id="$(var.JpProductCode)"
Name="$(var.JpAppName)"
Language="$(var.JpProductLanguage)"
Version="$(var.JpAppVersion)"
Manufacturer="$(var.JpAppVendor)"
UpgradeCode="$(var.JpProductUpgradeCode)">
<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x64"
/>
<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
<Upgrade Id="$(var.JpProductUpgradeCode)">
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
Property="JP_UPGRADABLE_FOUND"
Maximum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
Property="JP_DOWNGRADABLE_FOUND"
Minimum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
</Upgrade>
<?ifndef JpAllowUpgrades ?>
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
<?endif?>
<?ifndef JpAllowDowngrades ?>
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
<?endif?>
<!-- Standard required root -->
<Directory Id="TARGETDIR" Name="SourceDir"/>
<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
<ComponentGroupRef Id="Shortcuts"/>
<ComponentGroupRef Id="Files"/>
<ComponentGroupRef Id="FileAssociations"/>
<Component Id="pathEnvironmentVariable" Guid="{978ea978-79e0-0126-9ed7-77885b88d225}" KeyPath="yes" Directory="TARGETDIR">
<Environment Id="MyPathVariable" Name="Path" Value="[INSTALLDIR]" Action="set" System="no" Permanent="no" Part="last" Separator=";" />
</Component>
</Feature>
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
<CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
<CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
<CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" />
<?ifdef JpHelpURL ?>
<CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
<?endif?>
<?ifdef JpAboutURL ?>
<CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
<?endif?>
<?ifdef JpUpdateURL ?>
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
<?endif?>
<?ifdef JpIcon ?>
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
<?endif?>
<UIRef Id="JpUI"/>
<InstallExecuteSequence>
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCOMMENTS" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCONTACT" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPSIZE" After="CostFinalize">Not Installed</Custom>
<?ifdef JpHelpURL ?>
<Custom Action="JpSetARPHELPLINK" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpAboutURL ?>
<Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpUpdateURL ?>
<Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifndef JpAllowUpgrades ?>
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<?endif?>
<?ifndef JpAllowDowngrades ?>
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<?endif?>
<RemoveExistingProducts Before="CostInitialize"/>
</InstallExecuteSequence>
</Product>
</Wix>
```
## main.wxs - Update
```xml
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?ifdef JpIsSystemWide ?>
<?define JpInstallScope="perMachine"?>
<?else?>
<?define JpInstallScope="perUser"?>
<?endif?>
<?define JpProductLanguage=1033 ?>
<?define JpInstallerVersion=200 ?>
<?define JpCompressedMsi=yes ?>
<?ifdef JpAllowUpgrades ?>
<?define JpUpgradeVersionOnlyDetectUpgrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectUpgrade="yes"?>
<?endif?>
<?ifdef JpAllowDowngrades ?>
<?define JpUpgradeVersionOnlyDetectDowngrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
<?endif?>
<?include $(var.JpConfigDir)/overrides.wxi ?>
<Product
Id="$(var.JpProductCode)"
Name="$(var.JpAppName)"
Language="$(var.JpProductLanguage)"
Version="$(var.JpAppVersion)"
Manufacturer="$(var.JpAppVendor)"
UpgradeCode="$(var.JpProductUpgradeCode)">
<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x64"
/>
<util:CloseApplication Id="CloseMyApp"
Target="jpdfbookmarks.exe"
CloseMessage="yes"
RebootPrompt="no"
TerminateProcess="1" />
<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
<Upgrade Id="$(var.JpProductUpgradeCode)">
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
Property="JP_UPGRADABLE_FOUND"
Maximum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
Property="JP_DOWNGRADABLE_FOUND"
Minimum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
</Upgrade>
<?ifndef JpAllowUpgrades ?>
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
<?endif?>
<?ifndef JpAllowDowngrades ?>
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
<?endif?>
<Directory Id="TARGETDIR" Name="SourceDir"/>
<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
<ComponentGroupRef Id="Shortcuts"/>
<ComponentGroupRef Id="Files"/>
<ComponentGroupRef Id="FileAssociations"/>
<Component Id="pathEnvironmentVariable" Guid="{978ea978-79e0-0126-9ed7-77885b88d225}" KeyPath="yes" Directory="TARGETDIR">
<Environment Id="MyPathVariable" Name="Path" Value="[INSTALLDIR]" Action="set" System="no" Permanent="no" Part="last" Separator=";" />
</Component>
</Feature>
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
<CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
<CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
<CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" />
<?ifdef JpHelpURL ?>
<CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
<?endif?>
<?ifdef JpAboutURL ?>
<CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
<?endif?>
<?ifdef JpUpdateURL ?>
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
<?endif?>
<?ifdef JpIcon ?>
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
<?endif?>
<UIRef Id="JpUI"/>
<InstallExecuteSequence>
<Custom Action="WixCloseApplications" After="InstallInitialize" />
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCOMMENTS" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCONTACT" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPSIZE" After="CostFinalize">Not Installed</Custom>
<?ifdef JpHelpURL ?>
<Custom Action="JpSetARPHELPLINK" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpAboutURL ?>
<Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpUpdateURL ?>
<Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifndef JpAllowUpgrades ?>
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<?endif?>
<?ifndef JpAllowDowngrades ?>
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<?endif?>
<RemoveExistingProducts Before="CostInitialize"/>
</InstallExecuteSequence>
</Product>
</Wix>
```
Update 1 - Add `<util:CloseApplication Id="CloseMyApp" .... TerminateProcess="1"/>`
`TerminateProcess="1"`
```xml
<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x64"
/>
<util:CloseApplication Id="CloseMyApp"
Target="jpdfbookmarks.exe"
CloseMessage="yes"
RebootPrompt="no"
TerminateProcess="1" />
...
```
Update 2 - Add `<Custom Action="WixCloseApplications" After="InstallInitialize" />`
```xml
<InstallExecuteSequence>
<Custom Action="WixCloseApplications" After="InstallInitialize" />
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
...
```
If you wish to perform tests, after completing the modifications to main.wxs, execute the following batch files in sequence:
- build-installer-msi-pre-setup-JDK.bat
- build-installer-msi-pre-setup-WiX.bat
- build-installer-msi-3.0.2.bat
If everything goes smoothly, you'll get a jpdfbookmarks-3.0.2_x64.msi file for testing.
Test:
Run `jpdfbookmarks-3.0.2_x64.msi` install
Run Gui - `jpdfbookmarks.exe`
Uninstall jpdfbookmarks
It will popup a window , Select `Do not close application`, then click `OK`
jpdfbookmarks.exe will exit by Uninstaller.
I just tested it, and the removal function automatically closes any running GUI programs before completing the removal.
The solution is pretty simple here, create a resources dir and override main.wxs file and look for **Product** tag and set **Platform="x86"** incase of 64-bit it'll be **Platform="x64"**.
To get main.wxs file, you can run the jpackage command with **--temp temp-dir** [Jpackage temporary files][1].
<Product
Id="$(var.JpProductCode)"
Name="$(var.JpAppName)"
Language="$(var.JpProductLanguage)"
Version="$(var.JpAppVersion)"
Manufacturer="$(var.JpAppVendor)"
UpgradeCode="$(var.JpProductUpgradeCode)">
<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x86"
/>
[1]: https://docs.oracle.com/en/java/javase/17/jpackage/override-jpackage-resources.html#GUID-62412365-821D-4736-A20D-70F2D47136D8:~:text=Use%20the%20%2D%2Dtemp%20option%20to%20keep%20temporary%20files%20for%20review