Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9abaf09
Share pinterface calculation code with cppwinrt and precalc generic i…
DefaultRyan May 22, 2026
b9e9b02
Replace sprintf with a quick lookup table for hex digits
DefaultRyan May 22, 2026
e8b7167
Minor cleanup
DefaultRyan May 27, 2026
f5bab1f
Fix some calculations. Wrap guid_v and name_v specializations in prep…
DefaultRyan May 27, 2026
7c631fe
Precompute "standard" IReference<T> pinterfaces
DefaultRyan May 27, 2026
765f429
Fix shift-left underflow
DefaultRyan May 27, 2026
41e5bc0
Specialize pinterface_guid instead of guid_v. Friendlier to modules. …
DefaultRyan May 28, 2026
512a6d4
Wrap namespace and ifndef
DefaultRyan May 28, 2026
e94050f
Move manual IReference specializations from base_reference_produce in…
DefaultRyan May 28, 2026
5e58472
Typo in IReference<guid>
DefaultRyan May 28, 2026
81d2d02
Apply CoPilot suggestions from code review
DefaultRyan May 29, 2026
f8a9002
Synthesize GenericTypeInstSig for IReference specializations, instead…
DefaultRyan May 29, 2026
758a0a1
Remove leftover name_v machinery
DefaultRyan May 29, 2026
8ba0c2e
Update winmd nuget package to 1.0.260529.3 to fix build break
DefaultRyan May 29, 2026
68d98ab
Fix i686 cross-build by avoiding removed winmd signature constructors
Copilot May 30, 2026
9b1d5ee
Apply remaining changes
Copilot May 30, 2026
4780fb0
The problem was a pinned old version of winmd in the cmake files.
DefaultRyan May 30, 2026
0b2ac26
Merge branch 'master' into user/defaultryan/pinterface_precalc
DefaultRyan Jun 1, 2026
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ if(EXTERNAL_WINMD_INCLUDE_DIR STREQUAL "")
include(ExternalProject)
ExternalProject_Add(winmd
GIT_REPOSITORY https://github.com/microsoft/winmd.git
GIT_TAG 0f1eae3bfa63fa2ba3c2912cbfe72a01db94cc5a
GIT_TAG 1.0.260529.3
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
Expand Down
69 changes: 69 additions & 0 deletions cppwinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,23 @@ namespace cppwinrt
return { w, write_close_namespace };
}

[[nodiscard]] static finish_with wrap_extern_cpp_impl_namespace(writer& w)
{
w.write(R"(
extern "C++"
{
namespace winrt::impl
{
)");

return { w, [](writer& w) {
w.write(R"(
} // winrt::impl
} // extern "C++"
)");
}};
}

[[nodiscard]] static finish_with wrap_std_namespace(writer& w)
{
w.write(R"(namespace std
Expand Down Expand Up @@ -537,6 +554,58 @@ namespace cppwinrt
}
}

static std::string make_pinterface_guard(std::string_view const& cpp_name)
{
std::string guard = "WINRT_IMPL_PINTERFACE_GUID_";
guard.reserve(guard.size() + cpp_name.size());
for (char c : cpp_name)
{
if (c == ':' || c == '<' || c == '>' || c == ',' || c == ' ')
guard += '_';
else
guard += c;
}
return guard;
}

static void write_generic_inst_specializations(writer& w, std::map<std::string, generic_inst_info> const& instantiations)
{
if (instantiations.empty())
{
return;
}

// This block is self-contained (written outside any open namespace).
// extern "C++" attaches specializations to the global module so identical
// specializations across modules merge rather than collide.
// #ifndef guards prevent redefinition within a single TU (SCC-consolidated modules).
auto wrap_ns = wrap_extern_cpp_impl_namespace(w);

for (auto&& [cpp_name, info] : instantiations)
{
auto guard = make_pinterface_guard(cpp_name);
{
auto wrap_guard = wrap_ifndef(w, guard);
w.write("#define %\n", guard);
w.write(" template <> struct pinterface_guid<%>\n", cpp_name);
w.write(" {\n");
w.write(" static constexpr bool precomputed = true;\n");
w.write(" static constexpr guid value{ ");
auto& g = info.guid;
w.write_printf("0x%08X,0x%04X,0x%04X,{ 0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X }",
g.Data1, g.Data2, g.Data3,
g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],
g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
w.write(" }; // ");
w.write_printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
g.Data1, g.Data2, g.Data3,
g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3],
g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
w.write(" };\n");
}
}
}

static void write_struct_category(writer& w, TypeDef const& type)
{
auto format = R"( template <> struct category<%>{ using type = struct_category<%>; };
Expand Down
4 changes: 2 additions & 2 deletions cppwinrt/cppwinrt.vcxproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Windows.WinMD.1.0.210629.2\build\native\Microsoft.Windows.WinMD.props" Condition="Exists('..\packages\Microsoft.Windows.WinMD.1.0.210629.2\build\native\Microsoft.Windows.WinMD.props')" />
<Import Project="..\packages\Microsoft.Windows.WinMD.1.0.260529.3\build\native\Microsoft.Windows.WinMD.props" Condition="Exists('..\packages\Microsoft.Windows.WinMD.1.0.260529.3\build\native\Microsoft.Windows.WinMD.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
Expand Down Expand Up @@ -309,6 +309,6 @@
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Windows.WinMD.1.0.210629.2\build\native\Microsoft.Windows.WinMD.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.WinMD.1.0.210629.2\build\native\Microsoft.Windows.WinMD.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Windows.WinMD.1.0.260529.3\build\native\Microsoft.Windows.WinMD.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.WinMD.1.0.260529.3\build\native\Microsoft.Windows.WinMD.props'))" />
</Target>
</Project>
20 changes: 20 additions & 0 deletions cppwinrt/file_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,32 @@ namespace cppwinrt
w.write_each<write_guid>(members.interfaces);
w.write_each<write_guid>(members.delegates);
w.write_each<write_default_interface>(members.classes);

w.write_each<write_interface_abi>(members.interfaces);
w.write_each<write_delegate_abi>(members.delegates);
w.write_each<write_consume>(members.interfaces);
w.write_each<write_struct_abi>(members.structs);
}

// Emit pinterface_guid specializations AFTER the wrap_impl_namespace block
// so they don't break the WINRT_EXPORT attribute on subsequent declarations.
// The function writes a self-contained extern "C++" block.
{
std::map<std::string, generic_inst_info> instantiations;
collect_generic_instantiations(w, members, instantiations);

// For Windows.Foundation, also inject well-known IReference<T>/IReferenceArray<T>
// specializations for standard primitive and struct types. These ensure that
// consumers who only include Windows.Foundation.h get precomputed GUIDs for
// boxing types, without depending on other namespace headers.
if (ns == "Windows.Foundation")
{
add_well_known_ireference_instantiations(w, members, instantiations);
}

write_generic_inst_specializations(w, instantiations);
}

write_close_file_guard(w);
w.swap();
write_preamble(w);
Expand Down
Loading
Loading