From 2907321bd211ade73c78e28ce3c6f6948eba909f Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Tue, 12 May 2026 12:23:34 -0700 Subject: [PATCH 1/3] Fix LT-22509: Newtonsoft.Json Method not found error - Newtonsoft.Json doesn't change assembly versions on minor version bumps. 13.0.4 added a method and we started using it in libpalaso. If a version less than that is installed in the GAC our local version would not be loaded. This patch enforces using our local copy by our application. Change-Id: I9b7cdfbe792fda13b3dcc570c2c5dc8d19e6d596 --- .../Patch-NewtonsoftJsonPrivateCodeBase.ps1 | 39 +++++++++++++++++++ Build/Installer.legacy.targets | 9 +++++ Build/Installer.targets | 9 +++++ 3 files changed, 57 insertions(+) create mode 100644 Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 diff --git a/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 b/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 new file mode 100644 index 0000000000..a16b89191b --- /dev/null +++ b/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 @@ -0,0 +1,39 @@ +# Adds under Newtonsoft.Json dependentAssembly in staged *.config +# so the private 13.0.x DLL wins over an older same-identity (13.0.0.0) GAC build. Param: StagedBinDir. +param([Parameter(Mandatory)][string]$StagedBinDir) +$ErrorActionPreference = 'Stop' +$bin = if ($StagedBinDir) { [IO.Path]::GetFullPath($StagedBinDir) } +if (-not $bin -or -not (Test-Path -LiteralPath $bin -PathType Container)) { + Write-Verbose "Skip: staged bin missing: $StagedBinDir"; return +} +$nj = Join-Path $bin 'Newtonsoft.Json.dll' +if (-not (Test-Path -LiteralPath $nj -PathType Leaf)) { + Write-Verbose "Skip: Newtonsoft.Json.dll missing under $bin"; return +} +$ver = [Reflection.AssemblyName]::GetAssemblyName($nj).Version.ToString() +$ns = 'urn:schemas-microsoft-com:asm.v1' +Get-ChildItem -LiteralPath $bin -Filter '*.config' -File | ForEach-Object { + $path = $_.FullName + $xml = New-Object System.Xml.XmlDocument + try { $xml.Load($path) } catch { Write-Warning "Skip unreadable config $path : $_"; return } + $m = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) + [void]$m.AddNamespace('ab', $ns) + $deps = $xml.SelectNodes('//ab:dependentAssembly', $m) + if (-not $deps -or $deps.Count -eq 0) { return } + $changed = $false + foreach ($d in $deps) { + $id = $d.SelectSingleNode('ab:assemblyIdentity', $m) + if (-not $id -or $id.GetAttribute('name') -cne 'Newtonsoft.Json') { continue } + $ok = $false + foreach ($c in @($d.SelectNodes('ab:codeBase', $m))) { + if ($c.GetAttribute('href') -cne 'Newtonsoft.Json.dll') { continue } + if ($c.GetAttribute('version') -ceq $ver) { $ok = $true; break } + [void]$d.RemoveChild($c); $changed = $true + } + if ($ok) { continue } + $cb = $xml.CreateElement('codeBase', $ns) + $cb.SetAttribute('version', $ver); $cb.SetAttribute('href', 'Newtonsoft.Json.dll') + [void]$d.InsertAfter($cb, $id); $changed = $true + } + if ($changed) { $xml.Save($path) } +} diff --git a/Build/Installer.legacy.targets b/Build/Installer.legacy.targets index 52afd1e5bb..61e5fdb61c 100644 --- a/Build/Installer.legacy.targets +++ b/Build/Installer.legacy.targets @@ -350,6 +350,15 @@ OverwriteReadonlyFiles="true" DestinationFolder="$(OverridesDestDir)" /> + + + $(fwrt)\Build\Agent\Patch-NewtonsoftJsonPrivateCodeBase.ps1 + + diff --git a/Build/Installer.targets b/Build/Installer.targets index e787d15cdb..fac356a675 100644 --- a/Build/Installer.targets +++ b/Build/Installer.targets @@ -145,6 +145,15 @@ + + + $(fwrt)\Build\Agent\Patch-NewtonsoftJsonPrivateCodeBase.ps1 + + From 8bb42c2063c62991e720423c9d32bb356f63f461 Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Tue, 12 May 2026 12:23:34 -0700 Subject: [PATCH 2/3] Fix LT-22509: Newtonsoft.Json Method not found error - Newtonsoft.Json doesn't change assembly versions on minor version bumps. 13.0.4 added a method and we started using it in libpalaso. If a version less than that is installed in the GAC our local version would not be loaded. This patch enforces using our local copy by our application. Change-Id: I9b7cdfbe792fda13b3dcc570c2c5dc8d19e6d596 --- .../Patch-NewtonsoftJsonPrivateCodeBase.ps1 | 39 -- Build/Installer.legacy.targets | 17 +- Build/Installer.targets | 11 +- FLExInstaller/AGENTS.md | 6 + FLExInstaller/CustomComponents.wxi | 22 + .../PatchableInstallerHeatExclude.xml | 8 + .../wix6/FieldWorks.Installer.wixproj | 257 +++++------ FLExInstaller/wix6/Shared/Base/Framework.wxs | 418 +++++++++--------- FLExInstaller/wix6/Shared/Base/KeyPathFix.xsl | 80 +++- .../wix6/Shared/Base/heat-exclude.xml | 9 + .../wix6/Shared/Common/CustomComponents.wxi | 23 +- 11 files changed, 494 insertions(+), 396 deletions(-) delete mode 100644 Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 create mode 100644 FLExInstaller/PatchableInstallerHeatExclude.xml create mode 100644 FLExInstaller/wix6/Shared/Base/heat-exclude.xml diff --git a/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 b/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 deleted file mode 100644 index a16b89191b..0000000000 --- a/Build/Agent/Patch-NewtonsoftJsonPrivateCodeBase.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -# Adds under Newtonsoft.Json dependentAssembly in staged *.config -# so the private 13.0.x DLL wins over an older same-identity (13.0.0.0) GAC build. Param: StagedBinDir. -param([Parameter(Mandatory)][string]$StagedBinDir) -$ErrorActionPreference = 'Stop' -$bin = if ($StagedBinDir) { [IO.Path]::GetFullPath($StagedBinDir) } -if (-not $bin -or -not (Test-Path -LiteralPath $bin -PathType Container)) { - Write-Verbose "Skip: staged bin missing: $StagedBinDir"; return -} -$nj = Join-Path $bin 'Newtonsoft.Json.dll' -if (-not (Test-Path -LiteralPath $nj -PathType Leaf)) { - Write-Verbose "Skip: Newtonsoft.Json.dll missing under $bin"; return -} -$ver = [Reflection.AssemblyName]::GetAssemblyName($nj).Version.ToString() -$ns = 'urn:schemas-microsoft-com:asm.v1' -Get-ChildItem -LiteralPath $bin -Filter '*.config' -File | ForEach-Object { - $path = $_.FullName - $xml = New-Object System.Xml.XmlDocument - try { $xml.Load($path) } catch { Write-Warning "Skip unreadable config $path : $_"; return } - $m = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) - [void]$m.AddNamespace('ab', $ns) - $deps = $xml.SelectNodes('//ab:dependentAssembly', $m) - if (-not $deps -or $deps.Count -eq 0) { return } - $changed = $false - foreach ($d in $deps) { - $id = $d.SelectSingleNode('ab:assemblyIdentity', $m) - if (-not $id -or $id.GetAttribute('name') -cne 'Newtonsoft.Json') { continue } - $ok = $false - foreach ($c in @($d.SelectNodes('ab:codeBase', $m))) { - if ($c.GetAttribute('href') -cne 'Newtonsoft.Json.dll') { continue } - if ($c.GetAttribute('version') -ceq $ver) { $ok = $true; break } - [void]$d.RemoveChild($c); $changed = $true - } - if ($ok) { continue } - $cb = $xml.CreateElement('codeBase', $ns) - $cb.SetAttribute('version', $ver); $cb.SetAttribute('href', 'Newtonsoft.Json.dll') - [void]$d.InsertAfter($cb, $id); $changed = $true - } - if ($changed) { $xml.Save($path) } -} diff --git a/Build/Installer.legacy.targets b/Build/Installer.legacy.targets index 61e5fdb61c..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')) + @@ -350,15 +358,6 @@ OverwriteReadonlyFiles="true" DestinationFolder="$(OverridesDestDir)" /> - - - $(fwrt)\Build\Agent\Patch-NewtonsoftJsonPrivateCodeBase.ps1 - - diff --git a/Build/Installer.targets b/Build/Installer.targets index fac356a675..b77d361ec8 100644 --- a/Build/Installer.targets +++ b/Build/Installer.targets @@ -145,16 +145,7 @@ - - - $(fwrt)\Build\Agent\Patch-NewtonsoftJsonPrivateCodeBase.ps1 - - - + diff --git a/FLExInstaller/AGENTS.md b/FLExInstaller/AGENTS.md index 00b8b04317..60df705bb9 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`**), not in the generic PatchableInstaller tree. Wire them into **`Feature Complete`** with **`ComponentRef`** entries in **`PatchableInstaller/BaseInstallerBuild/Framework.wxs`** (FieldWorks Newtonsoft) and/or **`PatchableInstaller/Common/CustomFeatures.wxi`**; do not use **`FeatureRef Id="Complete"`** from an include that appears before **`Framework.wxs`** defines `Complete` (Light **LGHT0095**). Prefer **`Framework.wxs`** for wiring that must survive **`git checkout`** on **`PatchableInstaller/Common`** (LGHT0139 for GAC assemblies if refs are missing). + ## 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/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 From 63c5255820f81b6ce9eee8208076f86c2d7f5f47 Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Wed, 13 May 2026 15:27:13 -0700 Subject: [PATCH 3/3] Installer: Newtonsoft refs in CustomFeatures.wxi only Change-Id: I8255b5a9f413d76bb053a9a552ba6b08ad74b2fa --- FLExInstaller/AGENTS.md | 2 +- FLExInstaller/CustomFeatures.wxi | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/FLExInstaller/AGENTS.md b/FLExInstaller/AGENTS.md index 60df705bb9..55fc166094 100644 --- a/FLExInstaller/AGENTS.md +++ b/FLExInstaller/AGENTS.md @@ -12,7 +12,7 @@ Minimal installer guidance for agents. - 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`**), not in the generic PatchableInstaller tree. Wire them into **`Feature Complete`** with **`ComponentRef`** entries in **`PatchableInstaller/BaseInstallerBuild/Framework.wxs`** (FieldWorks Newtonsoft) and/or **`PatchableInstaller/Common/CustomFeatures.wxi`**; do not use **`FeatureRef Id="Complete"`** from an include that appears before **`Framework.wxs`** defines `Complete` (Light **LGHT0095**). Prefer **`Framework.wxs`** for wiring that must survive **`git checkout`** on **`PatchableInstaller/Common`** (LGHT0139 for GAC assemblies if refs are missing). +- 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 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 @@ + + + + +