From f35cbd72da295e3dff7b3bf3d091fbd80fcf6f1e Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 13:11:59 -0700 Subject: [PATCH 1/6] Fix WinRT host assembly probing Recognize the standard generic host filename without regard to case and generate renamed-host candidates only within the host directory. Fixes #2550 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 987e3253-f16a-4979-8175-d9ed9cea06ca --- src/Authoring/WinRT.Host/WinRT.Host.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Authoring/WinRT.Host/WinRT.Host.cpp b/src/Authoring/WinRT.Host/WinRT.Host.cpp index 82566f5995..9d90823924 100644 --- a/src/Authoring/WinRT.Host/WinRT.Host.cpp +++ b/src/Authoring/WinRT.Host/WinRT.Host.cpp @@ -273,13 +273,14 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul auto host_path = host_module; host_path.remove_filename(); - std::wstring target_path; + std::filesystem::path target_path; + std::wstring target_file; - std::vector probe_paths; + std::vector probe_paths; auto probe = [&](const wchar_t* suffix) { - auto probe_path = target_path + suffix; + auto probe_path = host_path / (target_file + suffix); auto end = probe_paths.end(); if (std::find(probe_paths.begin(), end, probe_path) == end) { @@ -292,16 +293,15 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul } return false; }; - auto shorten_target_path = [&]() { - std::size_t count = target_path.rfind('.'); + std::size_t count = target_file.rfind('.'); if (count == std::wstring::npos) { - target_path.clear(); + target_file.clear(); return false; } - target_path.resize(count); + target_file.resize(count); return true; }; @@ -312,11 +312,10 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul }; // Probe for target assembly by host name, if renamed (most common) - if (host_file.wstring() != L"winrt.host.dll") + if (::CompareStringOrdinal(host_file.c_str(), -1, L"WinRT.Host.dll", -1, TRUE) != CSTR_EQUAL) { probe_paths.push_back(host_module); - target_path = host_module; - target_path.resize(target_path.size() - 4); + target_file = host_file.stem().wstring(); if (probe_target()) { return target_path; @@ -324,7 +323,7 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul } // Probe for target assembly by runtime class name (less common) - target_path = host_path.wstring() + std::wstring(class_id.c_str()); + target_file = class_id.c_str(); if(probe_target()) { return target_path; From a3234090186326ff068dfb93d1684d3ff9e02d5a Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 19:58:03 -0700 Subject: [PATCH 2/6] Add WinRT host probe regression coverage Exercise renamed-host fallback from a dotted host directory while a conflicting assembly exists outside it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 987e3253-f16a-4979-8175-d9ed9cea06ca --- src/Authoring/WinRT.Host/WinRT.Host.cpp | 40 ++++++++++++++------- src/Tests/HostTest/Directory.Build.targets | 14 ++++++-- src/Tests/HostTest/DottedDirectory.manifest | 10 ++++++ src/Tests/HostTest/HostTest.vcxproj | 8 +++++ src/Tests/HostTest/HostTest.vcxproj.filters | 3 ++ src/Tests/HostTest/test.cpp | 11 +++++- 6 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 src/Tests/HostTest/DottedDirectory.manifest diff --git a/src/Authoring/WinRT.Host/WinRT.Host.cpp b/src/Authoring/WinRT.Host/WinRT.Host.cpp index 9d90823924..0cce90baa0 100644 --- a/src/Authoring/WinRT.Host/WinRT.Host.cpp +++ b/src/Authoring/WinRT.Host/WinRT.Host.cpp @@ -237,7 +237,9 @@ void init_runtime(const wchar_t* host_path, const wchar_t* host_config) } } -std::wstring find_mapped_target_assembly(std::filesystem::path host_config, winrt::hstring class_id) +std::wstring find_mapped_target_assembly( + std::filesystem::path const& host_config, + winrt::hstring const& class_id) { std::wstring target_assembly; @@ -267,11 +269,12 @@ std::wstring find_mapped_target_assembly(std::filesystem::path host_config, winr return target_assembly; } -std::filesystem::path probe_for_target_assembly(std::filesystem::path host_module, winrt::hstring class_id) +std::filesystem::path probe_for_target_assembly( + std::filesystem::path const& host_module, + winrt::hstring const& class_id) { - auto host_file = host_module.filename(); - auto host_path = host_module; - host_path.remove_filename(); + const auto host_file = host_module.filename(); + const auto host_path = host_module.parent_path(); std::filesystem::path target_path; std::wstring target_file; @@ -281,8 +284,8 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul auto probe = [&](const wchar_t* suffix) { auto probe_path = host_path / (target_file + suffix); - auto end = probe_paths.end(); - if (std::find(probe_paths.begin(), end, probe_path) == end) + if (std::find(probe_paths.begin(), probe_paths.end(), probe_path) + == probe_paths.end()) { if (std::filesystem::exists(probe_path)) { @@ -293,9 +296,10 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul } return false; }; - auto shorten_target_path = [&]() + + auto shorten_target_file = [&]() { - std::size_t count = target_file.rfind('.'); + const auto count = target_file.rfind('.'); if (count == std::wstring::npos) { target_file.clear(); @@ -307,12 +311,22 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul auto probe_target = [&]() { - while (!probe(L".Server.dll") && !probe(L".dll") && shorten_target_path()) {}; - return !target_path.empty(); + while (true) + { + if (probe(L".Server.dll") || probe(L".dll")) + { + return true; + } + if (!shorten_target_file()) + { + return false; + } + } }; // Probe for target assembly by host name, if renamed (most common) - if (::CompareStringOrdinal(host_file.c_str(), -1, L"WinRT.Host.dll", -1, TRUE) != CSTR_EQUAL) + if (::CompareStringOrdinal( + host_file.c_str(), -1, L"WinRT.Host.dll", -1, TRUE) != CSTR_EQUAL) { probe_paths.push_back(host_module); target_file = host_file.stem().wstring(); @@ -324,7 +338,7 @@ std::filesystem::path probe_for_target_assembly(std::filesystem::path host_modul // Probe for target assembly by runtime class name (less common) target_file = class_id.c_str(); - if(probe_target()) + if (probe_target()) { return target_path; } diff --git a/src/Tests/HostTest/Directory.Build.targets b/src/Tests/HostTest/Directory.Build.targets index d7428ead1c..22a1663ac0 100644 --- a/src/Tests/HostTest/Directory.Build.targets +++ b/src/Tests/HostTest/Directory.Build.targets @@ -16,7 +16,12 @@ $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll" + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(OutDir)WinRT.Host.runtimeconfig.json; + $(OutDir)WinRT.Host.Shim.dll; + $(OutDir)TestHost.ProbeByClass.dll; + $(OutDir)Test.dll" DestinationFiles=" $(OutDir)WinRT.Host.dll.mui; $(OutDir)WinRT.Host.dll; @@ -25,7 +30,12 @@ $(OutDir)ClassNotFound.Host.dll; $(OutDir)BadMappedTarget.Host.dll; $(OutDir)NoRuntimeConfig.Host.dll; - $(OutDir)RuntimeNotFound.Host.dll" + $(OutDir)RuntimeNotFound.Host.dll; + $(OutDir)Dotted.Directory\Unmatched.Host.dll; + $(OutDir)Dotted.Directory\Unmatched.Host.runtimeconfig.json; + $(OutDir)Dotted.Directory\WinRT.Host.Shim.dll; + $(OutDir)Dotted.Directory\TestHost.ProbeByClass.dll; + $(OutDir)Dotted.dll" UseHardlinksIfPossible="false" SkipUnchangedFiles="true" /> diff --git a/src/Tests/HostTest/DottedDirectory.manifest b/src/Tests/HostTest/DottedDirectory.manifest new file mode 100644 index 0000000000..58799a6ca3 --- /dev/null +++ b/src/Tests/HostTest/DottedDirectory.manifest @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Tests/HostTest/HostTest.vcxproj b/src/Tests/HostTest/HostTest.vcxproj index cbf8b3761d..ec98d6cee7 100644 --- a/src/Tests/HostTest/HostTest.vcxproj +++ b/src/Tests/HostTest/HostTest.vcxproj @@ -156,6 +156,14 @@ true true + + true + true + true + true + true + true + true true diff --git a/src/Tests/HostTest/HostTest.vcxproj.filters b/src/Tests/HostTest/HostTest.vcxproj.filters index 5c3e49c445..81325025f4 100644 --- a/src/Tests/HostTest/HostTest.vcxproj.filters +++ b/src/Tests/HostTest/HostTest.vcxproj.filters @@ -43,6 +43,9 @@ Manifest Files + + Manifest Files + Manifest Files diff --git a/src/Tests/HostTest/test.cpp b/src/Tests/HostTest/test.cpp index f0f01a51b8..dc567a2b9c 100644 --- a/src/Tests/HostTest/test.cpp +++ b/src/Tests/HostTest/test.cpp @@ -91,6 +91,16 @@ TEST(HostTest, ProbeByClass) EXPECT_TRUE(Activate(L"ProbeByClass.manifest") == L"TestHost.ProbeByClass.dll"); } +// ClassId: Host: Target: +// TestHost.ProbeByClass Dotted.Directory\Unmatched.Host.dll Dotted.Directory\TestHost.ProbeByClass.dll +// +// A renamed host must fall back to class-name probing without escaping a +// dotted host directory. +TEST(HostTest, ProbeByClassWithRenamedHostInDottedDirectory) +{ + EXPECT_TRUE(Activate(L"DottedDirectory.manifest") == L"TestHost.ProbeByClass.dll"); +} + // ClassId: Host: Target: // TestHost.Class Test.Host.dll Test.dll // @@ -139,4 +149,3 @@ TEST(HostTest, RuntimeConflict) { Activate(L"RuntimeNotFound.manifest", CoreHostIncompatibleConfig); } - From 9c13b07efb90bc84712ca650862406e68cc24baf Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 20:27:41 -0700 Subject: [PATCH 3/6] Cover missing target in dotted host directory Collapse HostTest deployment metadata and add a negative regression that rejects an escaped parent-directory candidate when the class-derived target is absent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 987e3253-f16a-4979-8175-d9ed9cea06ca --- src/Tests/HostTest/Directory.Build.targets | 10 +- .../DottedDirectoryTargetNotFound.manifest | 10 ++ src/Tests/HostTest/HostTest.vcxproj | 108 +++--------------- src/Tests/HostTest/HostTest.vcxproj.filters | 3 + src/Tests/HostTest/test.cpp | 7 ++ 5 files changed, 46 insertions(+), 92 deletions(-) create mode 100644 src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest diff --git a/src/Tests/HostTest/Directory.Build.targets b/src/Tests/HostTest/Directory.Build.targets index 22a1663ac0..0e61f1af90 100644 --- a/src/Tests/HostTest/Directory.Build.targets +++ b/src/Tests/HostTest/Directory.Build.targets @@ -21,7 +21,10 @@ $(OutDir)WinRT.Host.runtimeconfig.json; $(OutDir)WinRT.Host.Shim.dll; $(OutDir)TestHost.ProbeByClass.dll; - $(OutDir)Test.dll" + $(OutDir)Test.dll; + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(OutDir)WinRT.Host.runtimeconfig.json; + $(OutDir)WinRT.Host.Shim.dll" DestinationFiles=" $(OutDir)WinRT.Host.dll.mui; $(OutDir)WinRT.Host.dll; @@ -35,7 +38,10 @@ $(OutDir)Dotted.Directory\Unmatched.Host.runtimeconfig.json; $(OutDir)Dotted.Directory\WinRT.Host.Shim.dll; $(OutDir)Dotted.Directory\TestHost.ProbeByClass.dll; - $(OutDir)Dotted.dll" + $(OutDir)Dotted.dll; + $(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.dll; + $(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.runtimeconfig.json; + $(OutDir)Dotted.Directory.TargetNotFound\WinRT.Host.Shim.dll" UseHardlinksIfPossible="false" SkipUnchangedFiles="true" /> diff --git a/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest b/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest new file mode 100644 index 0000000000..960c83d463 --- /dev/null +++ b/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Tests/HostTest/HostTest.vcxproj b/src/Tests/HostTest/HostTest.vcxproj index ec98d6cee7..fba99ada4e 100644 --- a/src/Tests/HostTest/HostTest.vcxproj +++ b/src/Tests/HostTest/HostTest.vcxproj @@ -89,138 +89,71 @@ - true + true Document - true - true - true - true - true - true + true Document - true - true - true - true - true - true + true Document - true - true - true - true - true - true + true Document - true - true - true - true - true - true + true Document - true - true - true - true - true - true + true Document - true - true - true - true - true - true - true - true - true - true - true + true - true - true - true - true - true - true + true + + + true - true - true - true - true - true - true + true - true - true - true - true - true - true + true - true - true - true - true - true - true + true - true - true - true - true - true - true + true - true - true - true - true - true - true + true - true - true - true - true - true - true + true @@ -228,12 +161,7 @@ - true - true - true - true - true - true + true diff --git a/src/Tests/HostTest/HostTest.vcxproj.filters b/src/Tests/HostTest/HostTest.vcxproj.filters index 81325025f4..d76276b063 100644 --- a/src/Tests/HostTest/HostTest.vcxproj.filters +++ b/src/Tests/HostTest/HostTest.vcxproj.filters @@ -46,6 +46,9 @@ Manifest Files + + Manifest Files + Manifest Files diff --git a/src/Tests/HostTest/test.cpp b/src/Tests/HostTest/test.cpp index dc567a2b9c..eaa6bb0b02 100644 --- a/src/Tests/HostTest/test.cpp +++ b/src/Tests/HostTest/test.cpp @@ -101,6 +101,13 @@ TEST(HostTest, ProbeByClassWithRenamedHostInDottedDirectory) EXPECT_TRUE(Activate(L"DottedDirectory.manifest") == L"TestHost.ProbeByClass.dll"); } +TEST(HostTest, TargetNotFoundWithRenamedHostInDottedDirectory) +{ + Activate( + L"DottedDirectoryTargetNotFound.manifest", + HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)); +} + // ClassId: Host: Target: // TestHost.Class Test.Host.dll Test.dll // From eb004570590b68e2fd759d180737d39a806c7fa0 Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 20:57:47 -0700 Subject: [PATCH 4/6] Make WinRT host probing state explicit Replace capture-based local probe lambdas with helper functions that take immutable inputs and shared probe history explicitly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 987e3253-f16a-4979-8175-d9ed9cea06ca --- src/Authoring/WinRT.Host/WinRT.Host.cpp | 101 +++++++++++++----------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/src/Authoring/WinRT.Host/WinRT.Host.cpp b/src/Authoring/WinRT.Host/WinRT.Host.cpp index 0cce90baa0..ae4c42db51 100644 --- a/src/Authoring/WinRT.Host/WinRT.Host.cpp +++ b/src/Authoring/WinRT.Host/WinRT.Host.cpp @@ -4,6 +4,7 @@ #include "hostfxr_status.h" #include #include +#include #undef GetObject @@ -269,76 +270,84 @@ std::wstring find_mapped_target_assembly( return target_assembly; } -std::filesystem::path probe_for_target_assembly( - std::filesystem::path const& host_module, - winrt::hstring const& class_id) +bool probe_for_target_file_with_suffix( + std::filesystem::path const& host_path, + std::wstring const& target_file, + wchar_t const* suffix, + std::vector& probe_paths, + std::filesystem::path& target_path) { - const auto host_file = host_module.filename(); - const auto host_path = host_module.parent_path(); + auto probe_path = host_path / (target_file + suffix); + if (std::find(probe_paths.begin(), probe_paths.end(), probe_path) + != probe_paths.end()) + { + return false; + } - std::filesystem::path target_path; - std::wstring target_file; + if (std::filesystem::exists(probe_path)) + { + target_path = std::move(probe_path); + return true; + } - std::vector probe_paths; + probe_paths.emplace_back(std::move(probe_path)); + return false; +} - auto probe = [&](const wchar_t* suffix) +std::filesystem::path probe_for_target_file( + std::filesystem::path const& host_path, + std::wstring_view target_file, + std::vector& probe_paths) +{ + std::wstring candidate{target_file}; + + while (!candidate.empty()) { - auto probe_path = host_path / (target_file + suffix); - if (std::find(probe_paths.begin(), probe_paths.end(), probe_path) - == probe_paths.end()) + std::filesystem::path target_path; + if (probe_for_target_file_with_suffix( + host_path, candidate, L".Server.dll", probe_paths, target_path) + || probe_for_target_file_with_suffix( + host_path, candidate, L".dll", probe_paths, target_path)) { - if (std::filesystem::exists(probe_path)) - { - target_path = probe_path; - return true; - } - probe_paths.emplace_back(std::move(probe_path)); + return target_path; } - return false; - }; - auto shorten_target_file = [&]() - { - const auto count = target_file.rfind('.'); + const auto count = candidate.rfind('.'); if (count == std::wstring::npos) { - target_file.clear(); - return false; + return {}; } - target_file.resize(count); - return true; - }; + candidate.resize(count); + } - auto probe_target = [&]() - { - while (true) - { - if (probe(L".Server.dll") || probe(L".dll")) - { - return true; - } - if (!shorten_target_file()) - { - return false; - } - } - }; + return {}; +} + +std::filesystem::path probe_for_target_assembly( + std::filesystem::path const& host_module, + winrt::hstring const& class_id) +{ + const auto host_file = host_module.filename(); + const auto host_path = host_module.parent_path(); + + std::vector probe_paths; // Probe for target assembly by host name, if renamed (most common) if (::CompareStringOrdinal( host_file.c_str(), -1, L"WinRT.Host.dll", -1, TRUE) != CSTR_EQUAL) { probe_paths.push_back(host_module); - target_file = host_file.stem().wstring(); - if (probe_target()) + auto const target_file = host_file.stem().wstring(); + if (auto target_path = probe_for_target_file(host_path, target_file, probe_paths); + !target_path.empty()) { return target_path; } } // Probe for target assembly by runtime class name (less common) - target_file = class_id.c_str(); - if (probe_target()) + if (auto target_path = probe_for_target_file(host_path, class_id.c_str(), probe_paths); + !target_path.empty()) { return target_path; } From 9f93e591d8c5dc02b2f6cf133b61d31c5c143664 Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 22:07:51 -0700 Subject: [PATCH 5/6] Expand WinRT host probe regression coverage --- .../HostTest/ClassFallbackServer.manifest | 10 ++++++ src/Tests/HostTest/Directory.Build.targets | 34 +++++++++++++++++-- src/Tests/HostTest/HostTest.vcxproj | 9 +++++ src/Tests/HostTest/HostTest.vcxproj.filters | 9 +++++ .../HostTest/MixedCaseGenericHost.manifest | 10 ++++++ .../HostTest/MultiDotRenamedHost.manifest | 10 ++++++ src/Tests/HostTest/test.cpp | 19 +++++++++++ 7 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/Tests/HostTest/ClassFallbackServer.manifest create mode 100644 src/Tests/HostTest/MixedCaseGenericHost.manifest create mode 100644 src/Tests/HostTest/MultiDotRenamedHost.manifest diff --git a/src/Tests/HostTest/ClassFallbackServer.manifest b/src/Tests/HostTest/ClassFallbackServer.manifest new file mode 100644 index 0000000000..3b14727bc4 --- /dev/null +++ b/src/Tests/HostTest/ClassFallbackServer.manifest @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Tests/HostTest/Directory.Build.targets b/src/Tests/HostTest/Directory.Build.targets index 0e61f1af90..1d35ba651a 100644 --- a/src/Tests/HostTest/Directory.Build.targets +++ b/src/Tests/HostTest/Directory.Build.targets @@ -24,7 +24,22 @@ $(OutDir)Test.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; $(OutDir)WinRT.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll" + $(OutDir)WinRT.Host.Shim.dll; + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(OutDir)WinRT.Host.runtimeconfig.json; + $(OutDir)WinRT.Host.Shim.dll; + $(OutDir)TestHost.ProbeByClass.dll; + $(OutDir)Test.dll; + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(OutDir)Test.Host.runtimeconfig.json; + $(OutDir)WinRT.Host.Shim.dll; + $(OutDir)Test.dll; + $(OutDir)TestHost.ProbeByClass.dll; + $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; + $(OutDir)WinRT.Host.runtimeconfig.json; + $(OutDir)WinRT.Host.Shim.dll; + $(OutDir)TestHost.ProbeByClass.dll; + $(OutDir)TestHost.ProbeByClass.dll" DestinationFiles=" $(OutDir)WinRT.Host.dll.mui; $(OutDir)WinRT.Host.dll; @@ -41,7 +56,22 @@ $(OutDir)Dotted.dll; $(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.dll; $(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.runtimeconfig.json; - $(OutDir)Dotted.Directory.TargetNotFound\WinRT.Host.Shim.dll" + $(OutDir)Dotted.Directory.TargetNotFound\WinRT.Host.Shim.dll; + $(OutDir)MixedCaseGeneric\wInRt.HoSt.dll; + $(OutDir)MixedCaseGeneric\wInRt.HoSt.runtimeconfig.json; + $(OutDir)MixedCaseGeneric\WinRT.Host.Shim.dll; + $(OutDir)MixedCaseGeneric\TestHost.ProbeByClass.dll; + $(OutDir)MixedCaseGeneric\wInRt.dll; + $(OutDir)Multi.Dot.Host\Alpha.Beta.Host.dll; + $(OutDir)Multi.Dot.Host\Alpha.Beta.Host.runtimeconfig.json; + $(OutDir)Multi.Dot.Host\WinRT.Host.Shim.dll; + $(OutDir)Multi.Dot.Host\Alpha.Beta.Server.dll; + $(OutDir)Multi.Dot.Host\Alpha.Beta.dll; + $(OutDir)ClassFallbackServer\WinRT.Host.dll; + $(OutDir)ClassFallbackServer\WinRT.Host.runtimeconfig.json; + $(OutDir)ClassFallbackServer\WinRT.Host.Shim.dll; + $(OutDir)ClassFallbackServer\TestHost.Server.dll; + $(OutDir)ClassFallbackServer\TestHost.dll" UseHardlinksIfPossible="false" SkipUnchangedFiles="true" /> diff --git a/src/Tests/HostTest/HostTest.vcxproj b/src/Tests/HostTest/HostTest.vcxproj index fba99ada4e..6f02c4159f 100644 --- a/src/Tests/HostTest/HostTest.vcxproj +++ b/src/Tests/HostTest/HostTest.vcxproj @@ -127,6 +127,15 @@ true + + true + + + true + + + true + true diff --git a/src/Tests/HostTest/HostTest.vcxproj.filters b/src/Tests/HostTest/HostTest.vcxproj.filters index d76276b063..ff49708611 100644 --- a/src/Tests/HostTest/HostTest.vcxproj.filters +++ b/src/Tests/HostTest/HostTest.vcxproj.filters @@ -49,6 +49,15 @@ Manifest Files + + Manifest Files + + + Manifest Files + + + Manifest Files + Manifest Files diff --git a/src/Tests/HostTest/MixedCaseGenericHost.manifest b/src/Tests/HostTest/MixedCaseGenericHost.manifest new file mode 100644 index 0000000000..e6c339190d --- /dev/null +++ b/src/Tests/HostTest/MixedCaseGenericHost.manifest @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Tests/HostTest/MultiDotRenamedHost.manifest b/src/Tests/HostTest/MultiDotRenamedHost.manifest new file mode 100644 index 0000000000..5ff3fec262 --- /dev/null +++ b/src/Tests/HostTest/MultiDotRenamedHost.manifest @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/Tests/HostTest/test.cpp b/src/Tests/HostTest/test.cpp index eaa6bb0b02..0d27e41dd1 100644 --- a/src/Tests/HostTest/test.cpp +++ b/src/Tests/HostTest/test.cpp @@ -91,6 +91,18 @@ TEST(HostTest, ProbeByClass) EXPECT_TRUE(Activate(L"ProbeByClass.manifest") == L"TestHost.ProbeByClass.dll"); } +TEST(HostTest, ProbeByClassWithMixedCaseGenericHost) +{ + EXPECT_TRUE( + Activate(L"MixedCaseGenericHost.manifest") == + L"TestHost.ProbeByClass.dll"); +} + +TEST(HostTest, ProbeByClassUsesServerSuffixFirstWhenFallingBackToClassName) +{ + EXPECT_TRUE(Activate(L"ClassFallbackServer.manifest") == L"TestHost.Server.dll"); +} + // ClassId: Host: Target: // TestHost.ProbeByClass Dotted.Directory\Unmatched.Host.dll Dotted.Directory\TestHost.ProbeByClass.dll // @@ -108,6 +120,13 @@ TEST(HostTest, TargetNotFoundWithRenamedHostInDottedDirectory) HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)); } +TEST(HostTest, ProbeByHostUsesServerSuffixFirstWithMultiDotHostName) +{ + EXPECT_TRUE( + Activate(L"MultiDotRenamedHost.manifest") == + L"Alpha.Beta.Server.dll"); +} + // ClassId: Host: Target: // TestHost.Class Test.Host.dll Test.dll // From c48907237a9dd272a0846c7d5774e72df17ee457 Mon Sep 17 00:00:00 2001 From: "Chris Guzak (WINDOWS)" Date: Mon, 7 Sep 2026 22:45:42 -0700 Subject: [PATCH 6/6] Make WinRT host probe tests reliable --- .../HostTest/ClassFallbackServer.manifest | 2 +- src/Tests/HostTest/Directory.Build.targets | 55 +++++++++++++------ .../DottedDirectoryTargetNotFound.manifest | 2 +- src/Tests/HostTest/test.cpp | 8 +-- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/Tests/HostTest/ClassFallbackServer.manifest b/src/Tests/HostTest/ClassFallbackServer.manifest index 3b14727bc4..c38706c1c3 100644 --- a/src/Tests/HostTest/ClassFallbackServer.manifest +++ b/src/Tests/HostTest/ClassFallbackServer.manifest @@ -3,7 +3,7 @@ diff --git a/src/Tests/HostTest/Directory.Build.targets b/src/Tests/HostTest/Directory.Build.targets index 1d35ba651a..636cc4ede0 100644 --- a/src/Tests/HostTest/Directory.Build.targets +++ b/src/Tests/HostTest/Directory.Build.targets @@ -4,6 +4,10 @@ $(MSBuildProjectDirectory)/DoNotImport_MsAppxPackageTargets.targets CopyTestAssets;$(PrepareForRunDependsOn) + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)')) + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Projections\Test\bin', '$(Platform)', '$(Configuration)', 'net8.0')) + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Projections\TestHost.ProbeByClass\bin', '$(Platform)', '$(Configuration)', 'net8.0')) + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Authoring\WinRT.Host.Shim\bin', '$(Platform)', '$(Configuration)', 'net8.0')) @@ -18,28 +22,28 @@ $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(OutDir)WinRT.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll; - $(OutDir)TestHost.ProbeByClass.dll; - $(OutDir)Test.dll; + $(HostTestSourceDir)WinRT.Host.runtimeconfig.json; + $(WinRTHostShimOutDir)WinRT.Host.Shim.dll; + $(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll; + $(TestProjectionOutDir)Test.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(OutDir)WinRT.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll; + $(HostTestSourceDir)WinRT.Host.runtimeconfig.json; + $(WinRTHostShimOutDir)WinRT.Host.Shim.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(OutDir)WinRT.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll; - $(OutDir)TestHost.ProbeByClass.dll; - $(OutDir)Test.dll; + $(HostTestSourceDir)WinRT.Host.runtimeconfig.json; + $(WinRTHostShimOutDir)WinRT.Host.Shim.dll; + $(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll; + $(TestProjectionOutDir)Test.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(OutDir)Test.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll; - $(OutDir)Test.dll; - $(OutDir)TestHost.ProbeByClass.dll; + $(HostTestSourceDir)Test.Host.runtimeconfig.json; + $(WinRTHostShimOutDir)WinRT.Host.Shim.dll; + $(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll; + $(TestProjectionOutDir)Test.dll; $(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll; - $(OutDir)WinRT.Host.runtimeconfig.json; - $(OutDir)WinRT.Host.Shim.dll; - $(OutDir)TestHost.ProbeByClass.dll; - $(OutDir)TestHost.ProbeByClass.dll" + $(HostTestSourceDir)WinRT.Host.runtimeconfig.json; + $(WinRTHostShimOutDir)WinRT.Host.Shim.dll; + $(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll; + $(TestProjectionOutDir)Test.dll" DestinationFiles=" $(OutDir)WinRT.Host.dll.mui; $(OutDir)WinRT.Host.dll; @@ -73,6 +77,21 @@ $(OutDir)ClassFallbackServer\TestHost.Server.dll; $(OutDir)ClassFallbackServer\TestHost.dll" UseHardlinksIfPossible="false" SkipUnchangedFiles="true" /> + + + + + diff --git a/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest b/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest index 960c83d463..1960472350 100644 --- a/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest +++ b/src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest @@ -3,7 +3,7 @@ diff --git a/src/Tests/HostTest/test.cpp b/src/Tests/HostTest/test.cpp index 0d27e41dd1..a91c31b736 100644 --- a/src/Tests/HostTest/test.cpp +++ b/src/Tests/HostTest/test.cpp @@ -100,7 +100,7 @@ TEST(HostTest, ProbeByClassWithMixedCaseGenericHost) TEST(HostTest, ProbeByClassUsesServerSuffixFirstWhenFallingBackToClassName) { - EXPECT_TRUE(Activate(L"ClassFallbackServer.manifest") == L"TestHost.Server.dll"); + Activate(L"ClassFallbackServer.manifest", CLASS_E_CLASSNOTAVAILABLE); } // ClassId: Host: Target: @@ -115,16 +115,14 @@ TEST(HostTest, ProbeByClassWithRenamedHostInDottedDirectory) TEST(HostTest, TargetNotFoundWithRenamedHostInDottedDirectory) { - Activate( + Activate( L"DottedDirectoryTargetNotFound.manifest", HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)); } TEST(HostTest, ProbeByHostUsesServerSuffixFirstWithMultiDotHostName) { - EXPECT_TRUE( - Activate(L"MultiDotRenamedHost.manifest") == - L"Alpha.Beta.Server.dll"); + Activate(L"MultiDotRenamedHost.manifest", CLASS_E_CLASSNOTAVAILABLE); } // ClassId: Host: Target: