diff --git a/Directory.Build.targets b/Directory.Build.targets
index 9efab5a9a585..c9fac8a05b63 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -65,4 +65,19 @@
+
+
+
+
+ <_UnusedVCRuntimeDlls Include="$(OutDir)mfc140*.dll" />
+ <_UnusedVCRuntimeDlls Include="$(OutDir)mfcm140*.dll" />
+ <_UnusedVCRuntimeDlls Include="$(OutDir)vcamp140*.dll" />
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d083f672a1e8..c0a1d15e9ef1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -111,8 +111,7 @@
-
-
+
diff --git a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp
index 39786a16d886..75a3dceba50f 100644
--- a/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include "../../src/common/logger/logger.h"
@@ -1806,6 +1807,126 @@ void initSystemLogger()
} });
}
+UINT __stdcall CreateWinAppSDKHardlinksCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ std::wstring installationFolder;
+
+ hr = WcaInitialize(hInstall, "CreateWinAppSDKHardlinks");
+ ExitOnFailure(hr, "Failed to initialize");
+ hr = getInstallFolder(hInstall, installationFolder);
+ ExitOnFailure(hr, "Failed to get installFolder.");
+
+ {
+ namespace fs = std::filesystem;
+ const fs::path installDir(installationFolder);
+ const fs::path winui3Dir = installDir / L"WinUI3Apps";
+ const fs::path manifestPath = winui3Dir / L"hardlinks.txt";
+
+ if (!fs::exists(manifestPath))
+ {
+ WcaLog(LOGMSG_STANDARD, "CreateWinAppSDKHardlinks: No hardlinks.txt manifest found, skipping.");
+ goto LExit;
+ }
+
+ std::wifstream manifestFile(manifestPath);
+ std::wstring fileName;
+ int created = 0;
+ int failed = 0;
+
+ while (std::getline(manifestFile, fileName))
+ {
+ if (fileName.empty())
+ {
+ continue;
+ }
+
+ const fs::path source = installDir / fileName;
+ const fs::path target = winui3Dir / fileName;
+
+ if (!fs::exists(source))
+ {
+ WcaLog(LOGMSG_STANDARD, "CreateWinAppSDKHardlinks: Source not found: %ls", source.c_str());
+ failed++;
+ continue;
+ }
+
+ // Remove existing file if present (leftover from previous install)
+ std::error_code ec;
+ fs::remove(target, ec);
+
+ if (CreateHardLinkW(target.c_str(), source.c_str(), nullptr))
+ {
+ created++;
+ }
+ else
+ {
+ // Hard-link failed (e.g. cross-volume). Copy as fallback.
+ fs::copy_file(source, target, fs::copy_options::overwrite_existing, ec);
+ if (ec)
+ {
+ WcaLog(LOGMSG_STANDARD, "CreateWinAppSDKHardlinks: Failed to link or copy: %ls", fileName.c_str());
+ failed++;
+ }
+ else
+ {
+ created++;
+ }
+ }
+ }
+
+ WcaLog(LOGMSG_STANDARD, "CreateWinAppSDKHardlinks: Created %d links, %d failures", created, failed);
+ }
+
+LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
+UINT __stdcall DeleteWinAppSDKHardlinksCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ std::wstring installationFolder;
+
+ hr = WcaInitialize(hInstall, "DeleteWinAppSDKHardlinks");
+ ExitOnFailure(hr, "Failed to initialize");
+ hr = getInstallFolder(hInstall, installationFolder);
+ ExitOnFailure(hr, "Failed to get installFolder.");
+
+ {
+ namespace fs = std::filesystem;
+ const fs::path winui3Dir = fs::path(installationFolder) / L"WinUI3Apps";
+ const fs::path manifestPath = winui3Dir / L"hardlinks.txt";
+
+ if (!fs::exists(manifestPath))
+ {
+ goto LExit;
+ }
+
+ std::wifstream manifestFile(manifestPath);
+ std::wstring fileName;
+
+ while (std::getline(manifestFile, fileName))
+ {
+ if (fileName.empty())
+ {
+ continue;
+ }
+
+ std::error_code ec;
+ fs::remove(winui3Dir / fileName, ec);
+ }
+
+ WcaLog(LOGMSG_STANDARD, "DeleteWinAppSDKHardlinks: Cleaned up hard-linked files");
+ }
+
+LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
// DllMain - Initialize and cleanup WiX custom action utils.
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID)
{
diff --git a/installer/PowerToysSetupCustomActionsVNext/CustomAction.def b/installer/PowerToysSetupCustomActionsVNext/CustomAction.def
index 86efe34aa6b9..1b8b7d55f8a4 100644
--- a/installer/PowerToysSetupCustomActionsVNext/CustomAction.def
+++ b/installer/PowerToysSetupCustomActionsVNext/CustomAction.def
@@ -36,3 +36,5 @@ EXPORTS
SetBundleInstallLocationCA
InstallPackageIdentityMSIXCA
UninstallPackageIdentityMSIXCA
+ CreateWinAppSDKHardlinksCA
+ DeleteWinAppSDKHardlinksCA
diff --git a/installer/PowerToysSetupVNext/Product.wxs b/installer/PowerToysSetupVNext/Product.wxs
index 584d61c4497f..0086709578ae 100644
--- a/installer/PowerToysSetupVNext/Product.wxs
+++ b/installer/PowerToysSetupVNext/Product.wxs
@@ -111,6 +111,8 @@
+
+
@@ -123,6 +125,7 @@
+
@@ -136,6 +139,7 @@
+
@@ -188,8 +192,10 @@
+
+
diff --git a/installer/PowerToysSetupVNext/WinUI3Applications.wxs b/installer/PowerToysSetupVNext/WinUI3Applications.wxs
index 4c177b960a76..c0d3afb6f4ca 100644
--- a/installer/PowerToysSetupVNext/WinUI3Applications.wxs
+++ b/installer/PowerToysSetupVNext/WinUI3Applications.wxs
@@ -7,11 +7,18 @@
+
+
+
+
+
+
+
diff --git a/installer/PowerToysSetupVNext/generateAllFileComponents.ps1 b/installer/PowerToysSetupVNext/generateAllFileComponents.ps1
index 81445753690c..76e37020d4c6 100644
--- a/installer/PowerToysSetupVNext/generateAllFileComponents.ps1
+++ b/installer/PowerToysSetupVNext/generateAllFileComponents.ps1
@@ -30,6 +30,10 @@ Function Generate-FileList() {
$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*.png", "*.gif", "*.ico", "*.cur", "*.svg", "index.html", "reg.js", "gitignore.js", "srt.js", "monacoSpecialLanguages.js", "customTokenThemeRules.js", "*.pri")
+ # MFC DLLs leak into the output via WindowsAppSDKSelfContained but no PowerToys binary imports them.
+ # Verified with dumpbin /dependents across all 2176 binaries — zero consumers.
+ $fileExclusionList += @("mfc140.dll", "mfc140u.dll", "mfcm140.dll", "mfcm140u.dll")
+
$dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll")
if ($fileDepsJson -eq [string]::Empty) {
@@ -85,11 +89,16 @@ Function Generate-FileComponents() {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'fileList',
Justification = 'variable is used in another scope')]
- $fileList = $matches[2] -split ';'
+ $fileList = $matches[2] -split ';' | Where-Object { $_ -ne '' }
return
}
}
+ if ($null -eq $fileList -or $fileList.Count -eq 0) {
+ # No files to generate components for — leave placeholder intact
+ return
+ }
+
$componentId = "$($fileListName)_Component"
$componentDefs = "`r`n"
@@ -154,6 +163,49 @@ Generate-FileComponents -fileListName "BaseApplicationsFiles" -wxsFilePath $PSSc
#WinUI3Applications
Generate-FileList -fileDepsJson "" -fileListName WinUI3ApplicationsFiles -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
+
+# Deduplicate: Remove files from WinUI3Apps that are identical to root (same name + same hash).
+# These will be created as hard-links at install time by CreateWinAppSDKHardlinksCA.
+$rootPath = "$PSScriptRoot..\..\..\$platform\Release"
+$winui3Path = "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps"
+$winui3WxsPath = "$PSScriptRoot\WinUI3Applications.wxs"
+$winui3Wxs = Get-Content $winui3WxsPath -Raw
+$manifestPath = Join-Path $winui3Path "hardlinks.txt"
+
+if ($winui3Wxs -match "\<\?define WinUI3ApplicationsFiles=([^?]*)\?\>") {
+ $winui3FileList = $matches[1] -split ';' | Where-Object { $_ -ne '' }
+ $hardlinkFiles = @()
+
+ foreach ($file in $winui3FileList) {
+ $rootFile = Join-Path $rootPath $file
+ $winui3File = Join-Path $winui3Path $file
+ if ((Test-Path $rootFile) -and (Test-Path $winui3File)) {
+ $rootHash = (Get-FileHash $rootFile -Algorithm SHA256).Hash
+ $winui3Hash = (Get-FileHash $winui3File -Algorithm SHA256).Hash
+ if ($rootHash -eq $winui3Hash) {
+ $hardlinkFiles += $file
+ }
+ }
+ }
+
+ if ($hardlinkFiles.Count -gt 0) {
+ # Remove deduplicated files from WinUI3Apps file list
+ $remainingFiles = $winui3FileList | Where-Object { $_ -notin $hardlinkFiles }
+ if ($remainingFiles.Count -eq 0) {
+ # All files are duplicates — keep at least a dummy entry won't be emitted
+ # Generate-FileComponents handles empty defines by producing no entries
+ $winui3Wxs = $winui3Wxs -replace "\<\?define WinUI3ApplicationsFiles=[^?]*\?\>", ""
+ } else {
+ $winui3Wxs = $winui3Wxs -replace "\<\?define WinUI3ApplicationsFiles=[^?]*\?\>", ""
+ }
+ Set-Content -Path $winui3WxsPath -Value $winui3Wxs
+ Write-Host "Deduplicated $($hardlinkFiles.Count) files from WinUI3Apps (will be hard-linked at install time)"
+ }
+
+ # Always write hardlinks.txt (may be empty — CA handles that gracefully)
+ $hardlinkFiles | Set-Content -Path $manifestPath
+}
+
Generate-FileComponents -fileListName "WinUI3ApplicationsFiles" -wxsFilePath $PSScriptRoot\WinUI3Applications.wxs
#AdvancedPaste
diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs
index 144007e92f56..129fba3ce31a 100644
--- a/src/modules/MouseWithoutBorders/App/Class/Program.cs
+++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs
@@ -21,7 +21,6 @@
using System.Linq;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Principal;
-using System.ServiceModel.Channels;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj
index 4b3fc7fd50af..edc46f1118c3 100644
--- a/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj
+++ b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj
@@ -66,7 +66,7 @@
-
+
diff --git a/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj
index 675e927334e9..cd038f25fabd 100644
--- a/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj
+++ b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj
@@ -214,7 +214,7 @@
-
+
diff --git a/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj b/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj
index 53af161e16a5..b8787ba55958 100644
--- a/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj
+++ b/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj
@@ -71,7 +71,7 @@
-
+