diff --git a/Build/Installer.legacy.targets b/Build/Installer.legacy.targets
index 52afd1e5bb..fc0f808e07 100644
--- a/Build/Installer.legacy.targets
+++ b/Build/Installer.legacy.targets
@@ -156,7 +156,15 @@
$(fwrt)\Output\$(Configuration)
+ <_FieldWorksPatchableInstallerHeatExclude>$([MSBuild]::NormalizePath('$(fwrt)', 'FLExInstaller', 'PatchableInstallerHeatExclude.xml'))
+ <_PatchableInstallerHeatExcludeDest>$([MSBuild]::NormalizePath('$(fwrt)', 'PatchableInstaller', 'BaseInstallerBuild', 'heat-exclude.xml'))
+
diff --git a/Build/Installer.targets b/Build/Installer.targets
index e787d15cdb..b77d361ec8 100644
--- a/Build/Installer.targets
+++ b/Build/Installer.targets
@@ -145,7 +145,7 @@
-
+
diff --git a/FLExInstaller/AGENTS.md b/FLExInstaller/AGENTS.md
index 00b8b04317..55fc166094 100644
--- a/FLExInstaller/AGENTS.md
+++ b/FLExInstaller/AGENTS.md
@@ -8,6 +8,12 @@ Minimal installer guidance for agents.
- Validate prerequisites with `.\Build\Agent\Setup-InstallerBuild.ps1 -ValidateOnly`.
- Follow `.github/instructions/installer.instructions.md` for packaging and evidence rules.
+## WiX 3 (PatchableInstaller) notes
+
+- Heat exclusions: **`PatchableInstallerHeatExclude.xml`** is copied to **`PatchableInstaller/BaseInstallerBuild/heat-exclude.xml`** before Heat (see **`Build/Installer.legacy.targets`** `CopyFilesToInstall`).
+- **`buildMsi.bat`** passes **`-fv`** to **`light.exe`** so **`MsiAssemblyName`** includes **fileVersion** (same intent as MSBuild **`SetMsiAssemblyNameFileVersion=true`**), which helps GAC servicing when **`AssemblyVersion`** is unchanged but the binary’s **file version** increases.
+- Newtonsoft.Json and similar authored components live in **`CustomComponents.wxi`** (overlays **`PatchableInstaller/Common`**), with definitions guarded by **``** so patch/update authoring omits them when only **`UPDATEBUILDDIR`** is set. Add matching **`ComponentRef`** entries in **`FLExInstaller/CustomFeatures.wxi`** inside the **same** **`...`** so patch builds do not emit dangling refs (**LGHT0094**). WiX 6 **`Framework.wxs`** uses the same pattern for **`Feature Complete`**. Do not use **`FeatureRef Id="Complete"`** from an include that appears before **`Framework.wxs`** defines `Complete` (Light **LGHT0095**).
+
## Constraints
- Keep existing WiX 3 and WiX 6 flows intact.
diff --git a/FLExInstaller/CustomComponents.wxi b/FLExInstaller/CustomComponents.wxi
index 3e21099d2c..ac6602b63d 100644
--- a/FLExInstaller/CustomComponents.wxi
+++ b/FLExInstaller/CustomComponents.wxi
@@ -299,5 +299,27 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FLExInstaller/CustomFeatures.wxi b/FLExInstaller/CustomFeatures.wxi
index 4ba9e91287..4ae07481ce 100644
--- a/FLExInstaller/CustomFeatures.wxi
+++ b/FLExInstaller/CustomFeatures.wxi
@@ -10,6 +10,11 @@
+
+
+
+
+
diff --git a/FLExInstaller/PatchableInstallerHeatExclude.xml b/FLExInstaller/PatchableInstallerHeatExclude.xml
new file mode 100644
index 0000000000..cdf0687f6a
--- /dev/null
+++ b/FLExInstaller/PatchableInstallerHeatExclude.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/FLExInstaller/wix6/FieldWorks.Installer.wixproj b/FLExInstaller/wix6/FieldWorks.Installer.wixproj
index 681c791c3c..b5d6255559 100644
--- a/FLExInstaller/wix6/FieldWorks.Installer.wixproj
+++ b/FLExInstaller/wix6/FieldWorks.Installer.wixproj
@@ -1,166 +1,167 @@
- FieldWorks
- Package
- net48
- false
-
-
- {RawFileName};{HintPathFromItem};$(ReferencePaths)
-
-
- ICE60;ICE61
+ FieldWorks
+ Package
+ net48
+ false
+
+
+ {RawFileName};{HintPathFromItem};$(ReferencePaths)
+
+
+ ICE60;ICE61
- 1
- 0
+ 1
+ 0
- none
- true
- $(LinkerAdditionalOptions) -cc "$(IntermediateOutputPath)cabcache"
+ none
+ true
+ $(LinkerAdditionalOptions) -cc "$(IntermediateOutputPath)cabcache"
-
- objects\FieldWorks
- objects\FieldWorks_Data
- objects\FieldWorks_L10n
-
-
- FieldWorks
- FieldWorks
- SIL International
- SIL
- 9
- 3
- 9.3.0.1
- 1092269F-9EA1-419B-8685-90203F83E254
- *
-
-
- ProgramFiles64Folder
- ProgramFilesFolder
- CommonFiles64Folder
- CommonFilesFolder
-
- $(AppBuildDir)\$(BinDirSuffix)
- $(AppBuildDir)\$(DataDirSuffix)
- $(AppBuildDir)\$(L10nDirSuffix)
-
- ApplicationName=$(ApplicationName);SafeApplicationName=$(SafeApplicationName);Manufacturer=$(Manufacturer);SafeManufacturer=$(SafeManufacturer);MajorVersion=$(MajorVersion);MinorVersion=$(MinorVersion);VersionNumber=$(VersionNumber);ProductCode=$(ProductCode);UpgradeCode=$(UpgradeCode);PFDir=$(PFDir);CFDir=$(CFDir);MASTERBUILDDIR=$(MasterBuildDir);MASTERDATADIR=$(MasterDataDir);MASTERL10NDIR=$(MasterL10nDir);FastInstallerBuild=$(FastInstallerBuild);$(DefineConstants)
-
- <_MasterBuildDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterBuildDir)))
- <_MasterDataDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterDataDir)))
- <_MasterL10nDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterL10nDir)))
+
+ objects\FieldWorks
+ objects\FieldWorks_Data
+ objects\FieldWorks_L10n
+
+
+ FieldWorks
+ FieldWorks
+ SIL International
+ SIL
+ 9
+ 3
+ 9.3.0.1
+ 1092269F-9EA1-419B-8685-90203F83E254
+ *
+
+
+ ProgramFiles64Folder
+ ProgramFilesFolder
+ CommonFiles64Folder
+ CommonFilesFolder
+
+ $(AppBuildDir)\$(BinDirSuffix)
+ $(AppBuildDir)\$(DataDirSuffix)
+ $(AppBuildDir)\$(L10nDirSuffix)
+
+ ApplicationName=$(ApplicationName);SafeApplicationName=$(SafeApplicationName);Manufacturer=$(Manufacturer);SafeManufacturer=$(SafeManufacturer);MajorVersion=$(MajorVersion);MinorVersion=$(MinorVersion);VersionNumber=$(VersionNumber);ProductCode=$(ProductCode);UpgradeCode=$(UpgradeCode);PFDir=$(PFDir);CFDir=$(CFDir);MASTERBUILDDIR=$(MasterBuildDir);MASTERDATADIR=$(MasterDataDir);MASTERL10NDIR=$(MasterL10nDir);FastInstallerBuild=$(FastInstallerBuild);$(DefineConstants)
+
+ <_MasterBuildDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterBuildDir)))
+ <_MasterDataDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterDataDir)))
+ <_MasterL10nDirFull>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(MasterL10nDir)))
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
- <_HarvestDir>$(IntermediateOutputPath)Harvest\
- <_BaseDir>$(MSBuildProjectDirectory)\Shared\Base
-
- <_HeatExeFromRepo>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), ..\..\packages\wixtoolset.heat\6.0.2\tools\net472\x64\heat.exe))
- <_HeatExeFromNuGetRoot>$([MSBuild]::NormalizePath($(NuGetPackageRoot), wixtoolset.heat\6.0.2\tools\net472\x64\heat.exe))
- <_HeatExe Condition="Exists('$(_HeatExeFromRepo)')">$(_HeatExeFromRepo)
- <_HeatExe Condition="'$(_HeatExe)' == '' and Exists('$(_HeatExeFromNuGetRoot)')">$(_HeatExeFromNuGetRoot)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ <_HarvestDir>$(IntermediateOutputPath)Harvest\
+ <_BaseDir>$(MSBuildProjectDirectory)\Shared\Base
+
+ <_HeatExeFromRepo>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), ..\..\packages\wixtoolset.heat\6.0.2\tools\net472\x64\heat.exe))
+ <_HeatExeFromNuGetRoot>$([MSBuild]::NormalizePath($(NuGetPackageRoot), wixtoolset.heat\6.0.2\tools\net472\x64\heat.exe))
+ <_HeatExe Condition="Exists('$(_HeatExeFromRepo)')">$(_HeatExeFromRepo)
+ <_HeatExe Condition="'$(_HeatExe)' == '' and Exists('$(_HeatExeFromNuGetRoot)')">$(_HeatExeFromNuGetRoot)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/FLExInstaller/wix6/Shared/Base/Framework.wxs b/FLExInstaller/wix6/Shared/Base/Framework.wxs
index 602a952af6..848b5bcadf 100644
--- a/FLExInstaller/wix6/Shared/Base/Framework.wxs
+++ b/FLExInstaller/wix6/Shared/Base/Framework.wxs
@@ -1,212 +1,216 @@
+ xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ProductCode="$(var.ProductCode)"
+ UpgradeCode="$(var.UpgradeCode)"
+ Language="1033"
+ Version="$(var.VersionNumber)"
+ Manufacturer="$(var.Manufacturer)"
+ InstallerVersion="300"
+ Compressed="yes"
+ Scope="perMachine">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FLExInstaller/wix6/Shared/Base/KeyPathFix.xsl b/FLExInstaller/wix6/Shared/Base/KeyPathFix.xsl
index f2b577a02c..7e646c9bc2 100644
--- a/FLExInstaller/wix6/Shared/Base/KeyPathFix.xsl
+++ b/FLExInstaller/wix6/Shared/Base/KeyPathFix.xsl
@@ -1,7 +1,7 @@
-
+
@@ -15,4 +15,80 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FLExInstaller/wix6/Shared/Base/heat-exclude.xml b/FLExInstaller/wix6/Shared/Base/heat-exclude.xml
new file mode 100644
index 0000000000..7629b0dd49
--- /dev/null
+++ b/FLExInstaller/wix6/Shared/Base/heat-exclude.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/FLExInstaller/wix6/Shared/Common/CustomComponents.wxi b/FLExInstaller/wix6/Shared/Common/CustomComponents.wxi
index 2be9cd20db..46c5736c40 100644
--- a/FLExInstaller/wix6/Shared/Common/CustomComponents.wxi
+++ b/FLExInstaller/wix6/Shared/Common/CustomComponents.wxi
@@ -1,5 +1,5 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file