Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 60 additions & 38 deletions src/Authoring/WinRT.Host/WinRT.Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "hostfxr_status.h"
#include <filesystem>
#include <sstream>
#include <string_view>

#undef GetObject

Expand Down Expand Up @@ -237,7 +238,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;

Expand Down Expand Up @@ -267,65 +270,84 @@ 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)
bool probe_for_target_file_with_suffix(
std::filesystem::path const& host_path,
std::wstring const& target_file,
wchar_t const* suffix,
std::vector<std::filesystem::path>& probe_paths,
std::filesystem::path& target_path)
{
auto host_file = host_module.filename();
auto host_path = host_module;
host_path.remove_filename();
auto probe_path = host_path / (target_file + suffix);
if (std::find(probe_paths.begin(), probe_paths.end(), probe_path)
!= probe_paths.end())
{
return false;
}

if (std::filesystem::exists(probe_path))
{
target_path = std::move(probe_path);
return true;
}

std::wstring target_path;
probe_paths.emplace_back(std::move(probe_path));
return false;
}

std::vector<std::wstring> probe_paths;
std::filesystem::path probe_for_target_file(
std::filesystem::path const& host_path,
std::wstring_view target_file,
std::vector<std::filesystem::path>& probe_paths)
{
std::wstring candidate{target_file};

auto probe = [&](const wchar_t* suffix)
while (!candidate.empty())
{
auto probe_path = target_path + suffix;
auto end = probe_paths.end();
if (std::find(probe_paths.begin(), end, probe_path) == 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_path = [&]()
{
std::size_t count = target_path.rfind('.');
const auto count = candidate.rfind('.');
if (count == std::wstring::npos)
{
target_path.clear();
return false;
return {};
}
target_path.resize(count);
return true;
};
candidate.resize(count);
}

auto probe_target = [&]()
{
while (!probe(L".Server.dll") && !probe(L".dll") && shorten_target_path()) {};
return !target_path.empty();
};
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<std::filesystem::path> probe_paths;

// 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);
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_path = host_path.wstring() + std::wstring(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;
}
Expand Down
10 changes: 10 additions & 0 deletions src/Tests/HostTest/ClassFallbackServer.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CsWinRT.HostTest"/>
<file name="ClassFallbackServer\WinRT.Host.dll">
<activatableClass
name="TestHost.ProbeByHost"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
69 changes: 67 additions & 2 deletions src/Tests/HostTest/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<!--Work around WinUI assumption that client requires building PRI, etc -->
<MsAppxPackageTargets>$(MSBuildProjectDirectory)/DoNotImport_MsAppxPackageTargets.targets</MsAppxPackageTargets>
<PrepareForRunDependsOn>CopyTestAssets;$(PrepareForRunDependsOn)</PrepareForRunDependsOn>
<HostTestSourceDir>$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)'))</HostTestSourceDir>
<TestProjectionOutDir>$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Projections\Test\bin', '$(Platform)', '$(Configuration)', 'net8.0'))</TestProjectionOutDir>
<TestHostProbeByClassOutDir>$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Projections\TestHost.ProbeByClass\bin', '$(Platform)', '$(Configuration)', 'net8.0'))</TestHostProbeByClassOutDir>
<WinRTHostShimOutDir>$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\Authoring\WinRT.Host.Shim\bin', '$(Platform)', '$(Configuration)', 'net8.0'))</WinRTHostShimOutDir>
</PropertyGroup>

<!--Rename host/test dlls for various tests (requires disabling hardlinks)-->
Expand All @@ -16,7 +20,30 @@
$(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;
$(HostTestSourceDir)WinRT.Host.runtimeconfig.json;
$(WinRTHostShimOutDir)WinRT.Host.Shim.dll;
$(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll;
$(TestProjectionOutDir)Test.dll;
$(BuildOutDir)WinRT.Host\bin\WinRT.Host.dll;
$(HostTestSourceDir)WinRT.Host.runtimeconfig.json;
$(WinRTHostShimOutDir)WinRT.Host.Shim.dll;
$(BuildOutDir)WinRT.Host\bin\WinRT.Host.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;
$(HostTestSourceDir)Test.Host.runtimeconfig.json;
$(WinRTHostShimOutDir)WinRT.Host.Shim.dll;
$(TestHostProbeByClassOutDir)TestHost.ProbeByClass.dll;
$(TestProjectionOutDir)Test.dll;
$(BuildOutDir)WinRT.Host\bin\WinRT.Host.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;
Expand All @@ -25,7 +52,45 @@
$(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;
$(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.dll;
$(OutDir)Dotted.Directory.TargetNotFound\Unmatched.Host.runtimeconfig.json;
$(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" />
<Copy SourceFiles="$(OutDir)WinRT.Runtime.dll;$(OutDir)Microsoft.Windows.SDK.NET.dll"
DestinationFolder="$(OutDir)Dotted.Directory\"
UseHardlinksIfPossible="false" SkipUnchangedFiles="true" />
<Copy SourceFiles="$(OutDir)WinRT.Runtime.dll;$(OutDir)Microsoft.Windows.SDK.NET.dll"
DestinationFolder="$(OutDir)Dotted.Directory.TargetNotFound\"
UseHardlinksIfPossible="false" SkipUnchangedFiles="true" />
<Copy SourceFiles="$(OutDir)WinRT.Runtime.dll;$(OutDir)Microsoft.Windows.SDK.NET.dll"
DestinationFolder="$(OutDir)MixedCaseGeneric\"
UseHardlinksIfPossible="false" SkipUnchangedFiles="true" />
<Copy SourceFiles="$(OutDir)WinRT.Runtime.dll;$(OutDir)Microsoft.Windows.SDK.NET.dll"
DestinationFolder="$(OutDir)Multi.Dot.Host\"
UseHardlinksIfPossible="false" SkipUnchangedFiles="true" />
<Copy SourceFiles="$(OutDir)WinRT.Runtime.dll;$(OutDir)Microsoft.Windows.SDK.NET.dll"
DestinationFolder="$(OutDir)ClassFallbackServer\"
UseHardlinksIfPossible="false" SkipUnchangedFiles="true" />
</Target>

Expand Down
10 changes: 10 additions & 0 deletions src/Tests/HostTest/DottedDirectory.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CsWinRT.HostTest"/>
<file name="Dotted.Directory\Unmatched.Host.dll">
<activatableClass
name="TestHost.ProbeByClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
10 changes: 10 additions & 0 deletions src/Tests/HostTest/DottedDirectoryTargetNotFound.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CsWinRT.HostTest"/>
<file name="Dotted.Directory.TargetNotFound\Unmatched.Host.dll">
<activatableClass
name="TestHost.ClassNotFound"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
Loading
Loading